muttlike-imap 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. muttlike_imap-1.0.0/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
  2. muttlike_imap-1.0.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
  3. muttlike_imap-1.0.0/.github/ISSUE_TEMPLATE/feature_request.md +30 -0
  4. muttlike_imap-1.0.0/.github/dependabot.yml +11 -0
  5. muttlike_imap-1.0.0/.github/pull_request_template.md +29 -0
  6. muttlike_imap-1.0.0/.github/workflows/ci.yml +36 -0
  7. muttlike_imap-1.0.0/.github/workflows/release.yml +47 -0
  8. muttlike_imap-1.0.0/.gitignore +17 -0
  9. muttlike_imap-1.0.0/CHANGELOG.md +40 -0
  10. muttlike_imap-1.0.0/CODE_OF_CONDUCT.md +30 -0
  11. muttlike_imap-1.0.0/CONTRIBUTING.md +56 -0
  12. muttlike_imap-1.0.0/LICENSE +21 -0
  13. muttlike_imap-1.0.0/PKG-INFO +234 -0
  14. muttlike_imap-1.0.0/README.md +203 -0
  15. muttlike_imap-1.0.0/SECURITY.md +5 -0
  16. muttlike_imap-1.0.0/docs/openclaw.md +76 -0
  17. muttlike_imap-1.0.0/docs/pattern-syntax.md +156 -0
  18. muttlike_imap-1.0.0/docs/secrets.md +121 -0
  19. muttlike_imap-1.0.0/pyproject.toml +90 -0
  20. muttlike_imap-1.0.0/src/muttlike_imap/__init__.py +3 -0
  21. muttlike_imap-1.0.0/src/muttlike_imap/__main__.py +5 -0
  22. muttlike_imap-1.0.0/src/muttlike_imap/cli.py +110 -0
  23. muttlike_imap-1.0.0/src/muttlike_imap/client.py +176 -0
  24. muttlike_imap-1.0.0/src/muttlike_imap/config.py +163 -0
  25. muttlike_imap-1.0.0/src/muttlike_imap/dates.py +238 -0
  26. muttlike_imap-1.0.0/src/muttlike_imap/mailbox.py +89 -0
  27. muttlike_imap-1.0.0/src/muttlike_imap/output.py +27 -0
  28. muttlike_imap-1.0.0/src/muttlike_imap/parser.py +350 -0
  29. muttlike_imap-1.0.0/src/muttlike_imap/sizes.py +57 -0
  30. muttlike_imap-1.0.0/tests/__init__.py +0 -0
  31. muttlike_imap-1.0.0/tests/test_cli.py +140 -0
  32. muttlike_imap-1.0.0/tests/test_client.py +397 -0
  33. muttlike_imap-1.0.0/tests/test_config.py +232 -0
  34. muttlike_imap-1.0.0/tests/test_dates.py +251 -0
  35. muttlike_imap-1.0.0/tests/test_mailbox.py +70 -0
  36. muttlike_imap-1.0.0/tests/test_output.py +58 -0
  37. muttlike_imap-1.0.0/tests/test_parser.py +318 -0
  38. muttlike_imap-1.0.0/tests/test_sizes.py +60 -0
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: Bug report
3
+ about: Report a bug or unexpected behaviour in muttlike-imap
4
+ title: ''
5
+ labels: bug
6
+ ---
7
+
8
+ ## Environment
9
+
10
+ - **muttlike-imap version**: <!-- output of `muttlike-imap --version` -->
11
+ - **Python version**: <!-- output of `python3 --version` -->
12
+ - **Operating system**: <!-- e.g. Ubuntu 24.04, macOS 14, Debian 12 -->
13
+ - **IMAP server**: <!-- e.g. Dovecot, Cyrus, Gmail, Fastmail, etc. -->
14
+
15
+ ## Describe the bug
16
+
17
+ <!-- A clear and concise description of what you expected and what actually happened. -->
18
+
19
+ ## Reproducer
20
+
21
+ <!--
22
+ The exact command line you ran. Redact mailbox or address details if
23
+ you need to, but please keep the pattern argument intact -- it's the
24
+ part most likely to be at fault.
25
+ -->
26
+
27
+ ```sh
28
+ muttlike-imap "..." --mailbox INBOX --summary
29
+ ```
30
+
31
+ ## Expected output
32
+
33
+ <!-- What you expected the command to return or do. -->
34
+
35
+ ## Actual output
36
+
37
+ <!-- The error message or wrong result you observed. Paste it in full. -->
@@ -0,0 +1,8 @@
1
+ blank_issues_enabled: true
2
+ contact_links:
3
+ - name: Pattern syntax reference
4
+ url: https://github.com/PierreSenellart/muttlike-imap/blob/main/docs/pattern-syntax.md
5
+ about: Full reference for the mutt-style pattern grammar.
6
+ - name: Storing the IMAP password securely
7
+ url: https://github.com/PierreSenellart/muttlike-imap/blob/main/docs/secrets.md
8
+ about: Worked examples with pass, gpg, and OS keyrings.
@@ -0,0 +1,30 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest a new modifier, CLI flag, or behaviour improvement
4
+ title: ''
5
+ labels: enhancement
6
+ ---
7
+
8
+ ## Use case
9
+
10
+ <!--
11
+ What problem are you trying to solve? A concrete scenario
12
+ ("I want to find X but currently have to ...") helps more than an
13
+ abstract request.
14
+ -->
15
+
16
+ ## Proposed solution
17
+
18
+ <!--
19
+ What would the feature look like from a user's perspective? If you
20
+ have a concrete CLI shape or pattern syntax in mind, show an example
21
+ invocation.
22
+ -->
23
+
24
+ ## Alternatives considered
25
+
26
+ <!-- Other ways to solve the same problem; why they're less suitable. -->
27
+
28
+ ## Background / references
29
+
30
+ <!-- Pointers to mutt's documentation, RFCs, or related tools that are relevant. Optional. -->
@@ -0,0 +1,11 @@
1
+ # To get started with Dependabot version updates, you'll need to specify which
2
+ # package ecosystems to update and where the package manifests are located.
3
+ # Please see the documentation for all configuration options:
4
+ # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5
+
6
+ version: 2
7
+ updates:
8
+ - package-ecosystem: "github-actions" # See documentation for possible values
9
+ directory: "/" # Location of package manifests
10
+ schedule:
11
+ interval: "weekly"
@@ -0,0 +1,29 @@
1
+ <!-- Thanks for contributing to muttlike-imap! -->
2
+
3
+ ## Summary
4
+
5
+ <!-- What does this PR change? One or two sentences. -->
6
+
7
+ ## Motivation
8
+
9
+ <!--
10
+ Why is this change necessary? Link to the related issue if applicable:
11
+
12
+ Closes #123
13
+ Fixes #456
14
+ -->
15
+
16
+ ## Checklist
17
+
18
+ - [ ] `pytest` passes locally (no IMAP server needed for the default suite)
19
+ - [ ] `ruff check .` and `ruff format --check .` pass
20
+ - [ ] Tests added or updated for any code change
21
+ - [ ] `CHANGELOG.md` entry added under `[Unreleased]`
22
+ - [ ] User-visible behaviour reflected in `README.md`, `docs/pattern-syntax.md`, or `docs/secrets.md` as appropriate
23
+
24
+ ## Notes for reviewers
25
+
26
+ <!--
27
+ Anything reviewers should pay extra attention to? Sharp edges,
28
+ performance trade-offs, IMAP-protocol surprises, etc.
29
+ -->
@@ -0,0 +1,36 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ lint:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v6
17
+ - uses: actions/setup-python@v6
18
+ with:
19
+ python-version: "3.12"
20
+ - run: pip install ruff
21
+ - run: ruff check .
22
+ - run: ruff format --check .
23
+
24
+ test:
25
+ runs-on: ubuntu-latest
26
+ strategy:
27
+ fail-fast: false
28
+ matrix:
29
+ python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
30
+ steps:
31
+ - uses: actions/checkout@v6
32
+ - uses: actions/setup-python@v6
33
+ with:
34
+ python-version: ${{ matrix.python-version }}
35
+ - run: pip install -e ".[dev]"
36
+ - run: pytest --cov --cov-report=term-missing
@@ -0,0 +1,47 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ build:
14
+ name: Build sdist and wheel
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v6
18
+ - uses: actions/setup-python@v6
19
+ with:
20
+ python-version: "3.12"
21
+ - name: Install build
22
+ run: python -m pip install --upgrade build
23
+ - name: Build distribution
24
+ run: python -m build
25
+ - name: Upload distribution artifacts
26
+ uses: actions/upload-artifact@v4
27
+ with:
28
+ name: distribution
29
+ path: dist/
30
+
31
+ publish:
32
+ name: Publish to PyPI
33
+ needs: build
34
+ runs-on: ubuntu-latest
35
+ environment:
36
+ name: pypi
37
+ url: https://pypi.org/p/muttlike-imap
38
+ permissions:
39
+ id-token: write
40
+ steps:
41
+ - name: Download distribution artifacts
42
+ uses: actions/download-artifact@v4
43
+ with:
44
+ name: distribution
45
+ path: dist/
46
+ - name: Publish to PyPI
47
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,17 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+ .eggs/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ .mypy_cache/
11
+ .coverage
12
+ htmlcov/
13
+ .tox/
14
+ .venv/
15
+ venv/
16
+ *.swp
17
+ .DS_Store
@@ -0,0 +1,40 @@
1
+ # Changelog
2
+
3
+ All notable changes are documented here. The format is loosely based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
5
+ adheres to [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [1.0.0]: Initial release
10
+
11
+ First public release.
12
+
13
+ ### Added
14
+ - Mutt-compatible pattern parser supporting AND (juxtaposition), `|` OR,
15
+ `!` NOT, and `(...)` grouping.
16
+ - Text modifiers: `~f`, `~t`, `~s`, `~b`, `~B`, `~c`, `~C`, `~L`, `~e`, `~i`,
17
+ `~y`, `~h`, `~x`.
18
+ - Flag modifiers: `~A`, `~U`, `~N`, `~R`, `~O`, `~F`, `~D`, `~Q`, `~p`, `~P`.
19
+ - Date modifiers `~d` and `~r` with the full mutt DATERANGE grammar:
20
+ relative (`<Nu`, `>Nu`, `=Nu`), absolute (`D/M/Y` and ISO `YYYY-MM-DD`),
21
+ ranges, half-open ranges, and error margins (`*Nu`). Sub-day units
22
+ (`H`/`M`/`S`) get day-rounded server-side filtering plus a Python
23
+ post-filter against `Date:` (or `INTERNALDATE` for `~r`), recovering
24
+ precise sub-day windows like `~d <30M` for "last 30 minutes".
25
+ - Size modifier `~z` with `<`, `>`, range, and inclusive/exclusive forms.
26
+ - `--list-mailboxes` for folder discovery.
27
+ - Modified UTF-7 (RFC 3501 §5.1.3) encoding/decoding for non-ASCII folder
28
+ names like `Éléments envoyés`.
29
+ - ASCII diacritic folding so `~f Müller` matches both UTF-8 and ASCII forms.
30
+ - Layered config: CLI flags > `IMAPQUERY_*` env vars > `$IMAPQUERY_CONFIG` >
31
+ `~/.config/muttlike-imap/config` > legacy `~/.config/imap-smtp-email/.env`.
32
+ - `--imap-password-cmd` flag and `IMAP_PASS_CMD` config key for fetching the
33
+ password from `pass`, `gpg`, `secret-tool`, the macOS Keychain, etc.,
34
+ without storing it on disk or exporting it through the environment.
35
+ - `--imap-password-env` flag for picking up an already-set environment
36
+ variable.
37
+ - Library API: `parse_pattern`, `search`, `list_mailboxes`, `load_config`.
38
+
39
+ [Unreleased]: https://github.com/PierreSenellart/muttlike-imap/compare/v1.0.0...HEAD
40
+ [1.0.0]: https://github.com/PierreSenellart/muttlike-imap/releases/tag/v1.0.0
@@ -0,0 +1,30 @@
1
+ # Code of Conduct
2
+
3
+ `muttlike-imap` is a small open-source utility. Most interaction happens
4
+ through GitHub issues and pull requests; this code of conduct sets the
5
+ basic expectations for those exchanges.
6
+
7
+ ## Expected behavior
8
+
9
+ - Be respectful and constructive in all interactions: issues, pull
10
+ requests, code reviews, and any other discussion.
11
+ - Welcome newcomers, especially first-time contributors.
12
+ - Accept constructive criticism gracefully; offer it the same way.
13
+
14
+ ## Unacceptable behavior
15
+
16
+ - Harassment, intimidation, or discrimination of any kind.
17
+ - Personal attacks or derogatory comments.
18
+ - Publishing others' private information without consent.
19
+
20
+ ## Scope
21
+
22
+ This code of conduct applies to all project spaces: the GitHub
23
+ repository, issue tracker, pull requests, and any other communication
24
+ channel associated with the project.
25
+
26
+ ## Enforcement
27
+
28
+ Instances of unacceptable behavior may be reported to the project
29
+ maintainer, [Pierre Senellart](mailto:pierre@senellart.com). Reports
30
+ will be handled confidentially.
@@ -0,0 +1,56 @@
1
+ # Contributing to muttlike-imap
2
+
3
+ Thank you for your interest in contributing to muttlike-imap!
4
+
5
+ ## Reporting bugs and requesting features
6
+
7
+ Please use the [GitHub issue
8
+ tracker](https://github.com/PierreSenellart/muttlike-imap/issues). Two
9
+ issue templates are provided and will auto-fill when you open a new
10
+ issue: a bug-report form (asking for `muttlike-imap --version`, your
11
+ Python version, OS, and a reproducer) and a feature-request form. For
12
+ security vulnerabilities, please use the [private security
13
+ advisory](https://github.com/PierreSenellart/muttlike-imap/security/advisories/new)
14
+ flow instead of a public issue (see [SECURITY.md](SECURITY.md)).
15
+
16
+ ## Development setup
17
+
18
+ ```sh
19
+ git clone https://github.com/PierreSenellart/muttlike-imap
20
+ cd muttlike-imap
21
+ pip install -e ".[dev]"
22
+ ```
23
+
24
+ That installs `ruff` (lint + format) and `pytest` (with `pytest-cov`)
25
+ into your current Python. The package itself has no runtime
26
+ dependencies.
27
+
28
+ ## Running the tests and linters
29
+
30
+ ```sh
31
+ pytest # full suite, ~240 tests, no IMAP server needed
32
+ pytest --cov # with coverage
33
+ ruff check . # lint
34
+ ruff format --check . # check formatting
35
+ ruff format . # apply formatting
36
+ ```
37
+
38
+ CI runs the same commands across Python 3.9 through 3.13.
39
+
40
+ ## Submitting a pull request
41
+
42
+ 1. Fork the repository and create a branch from `main`.
43
+ 2. Make your changes. Add or update tests for any code change: the bar
44
+ is "the test would have caught this bug" or "the test demonstrates
45
+ the new behaviour".
46
+ 3. Ensure `pytest`, `ruff check .`, and `ruff format --check .` pass.
47
+ 4. Update `CHANGELOG.md` under `[Unreleased]` with a one-line summary,
48
+ and update `README.md` / `docs/pattern-syntax.md` / `docs/secrets.md`
49
+ if you change user-visible behaviour.
50
+ 5. Open a pull request against `main` with a clear description of what
51
+ the change does and why.
52
+
53
+ ## License
54
+
55
+ By contributing, you agree that your contributions will be licensed
56
+ under the [MIT License](LICENSE).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pierre Senellart
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,234 @@
1
+ Metadata-Version: 2.4
2
+ Name: muttlike-imap
3
+ Version: 1.0.0
4
+ Summary: Search IMAP mailboxes from the command line using mutt-style patterns.
5
+ Project-URL: Homepage, https://github.com/PierreSenellart/muttlike-imap
6
+ Project-URL: Issues, https://github.com/PierreSenellart/muttlike-imap/issues
7
+ Project-URL: Changelog, https://github.com/PierreSenellart/muttlike-imap/blob/main/CHANGELOG.md
8
+ Author-email: Pierre Senellart <pierre@senellart.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: cli,email,imap,mutt,search
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Communications :: Email
24
+ Classifier: Topic :: Utilities
25
+ Requires-Python: >=3.9
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest-cov; extra == 'dev'
28
+ Requires-Dist: pytest>=7; extra == 'dev'
29
+ Requires-Dist: ruff; extra == 'dev'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # muttlike-imap
33
+
34
+ [![CI](https://github.com/PierreSenellart/muttlike-imap/actions/workflows/ci.yml/badge.svg)](https://github.com/PierreSenellart/muttlike-imap/actions/workflows/ci.yml)
35
+ [![PyPI](https://img.shields.io/pypi/v/muttlike-imap.svg)](https://pypi.org/project/muttlike-imap/)
36
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
37
+
38
+ Search IMAP mailboxes from the command line using mutt-style patterns.
39
+
40
+ ```console
41
+ $ muttlike-imap "~f alice ~U" --summary
42
+ 1 result(s):
43
+
44
+ UID:1264 | From:Alice <alice@example.com> | Date:Tue, 21 Apr 2026 15:02:35 +0000
45
+ Subject:Re: project update
46
+ Preview:Hi, here is the latest version of the document…
47
+ ```
48
+
49
+ ## Why
50
+
51
+ Mutt has a great pattern language for finding messages (`~f`, `~s`, `~d <7d`,
52
+ `!~U`, `(A | B) C`, …). IMAP servers can do most of the same searches, but the
53
+ wire protocol is verbose and the bindings in `imaplib` are awkward to compose.
54
+ `muttlike-imap` is a small CLI that translates mutt patterns into IMAP `SEARCH`
55
+ criteria and prints the matches as JSON or a human-readable summary.
56
+
57
+ It's intentionally small and scriptable – useful as a building block for
58
+ notification scripts, AI assistants, cron jobs, or one-off lookups.
59
+
60
+ ## Install
61
+
62
+ ```sh
63
+ pip install muttlike-imap
64
+ ```
65
+
66
+ Requires Python 3.9+. No third-party dependencies.
67
+
68
+ ## Configure
69
+
70
+ `muttlike-imap` looks for connection settings in this order (highest priority
71
+ first):
72
+
73
+ 1. CLI flags: `--imap-host`, `--imap-port`, `--imap-user`,
74
+ `--imap-password-cmd`, `--imap-password-env`, `--imap-tls`.
75
+ 2. Environment variables: `IMAPQUERY_HOST`, `IMAPQUERY_PORT`, `IMAPQUERY_USER`,
76
+ `IMAPQUERY_PASS`, `IMAPQUERY_TLS`.
77
+ 3. The file pointed to by `$IMAPQUERY_CONFIG`, if set.
78
+ 4. `$XDG_CONFIG_HOME/muttlike-imap/config` (defaults to
79
+ `~/.config/muttlike-imap/config`).
80
+ 5. `~/.config/imap-smtp-email/.env`: kept as a fallback for users who already
81
+ have this file from the
82
+ [openclaw imap-smtp-email skill](https://github.com/openclaw/imap-smtp-email).
83
+ See [`docs/openclaw.md`](docs/openclaw.md) for wiring `muttlike-imap`
84
+ into an openclaw workspace.
85
+
86
+ A minimal config file:
87
+
88
+ ```ini
89
+ IMAP_HOST=imap.example.com
90
+ IMAP_PORT=993
91
+ IMAP_USER=you@example.com
92
+ IMAP_PASS_CMD=pass email/imap.example.com
93
+ IMAP_TLS=true
94
+ ```
95
+
96
+ The keys can be written with the `IMAP_` prefix (shown above, matches mutt and
97
+ offlineimap conventions), with the `IMAPQUERY_` prefix, or with no prefix at
98
+ all (`HOST=…`); pick whichever you prefer.
99
+
100
+ ### Passwords
101
+
102
+ There are three ways to give `muttlike-imap` your password, in increasing
103
+ order of how much they leak:
104
+
105
+ - **`IMAP_PASS_CMD=<shell command>`** (recommended). The command is run on
106
+ every invocation; the first line of stdout is used as the password. Pair
107
+ with [`pass`](https://www.passwordstore.org/),
108
+ [`secret-tool`](https://wiki.gnome.org/Projects/Libsecret),
109
+ macOS Keychain (`security find-generic-password -w`), or anything else
110
+ that prints a secret to stdout. The password lives only in the
111
+ `muttlike-imap` process memory and is never written to disk or to the
112
+ environment.
113
+
114
+ Equivalent CLI flag: `--imap-password-cmd "pass email/imap.example.com"`.
115
+
116
+ - **`--imap-password-env MY_VAR`**. Reads the password from a named
117
+ environment variable. Useful when you already have a secret in a variable
118
+ (e.g. via `direnv` or a parent process) and don't want to re-export it.
119
+ Caveat: env vars leak through `/proc/<pid>/environ`, child processes,
120
+ `ps eww`, and crash dumps.
121
+
122
+ - **`IMAP_PASS=<plaintext>`** in the config file. Simplest, least secure;
123
+ fine for throwaway accounts and local-only setups. Make sure the file is
124
+ `chmod 600`.
125
+
126
+ See [`docs/secrets.md`](docs/secrets.md) for worked examples with `pass`,
127
+ raw `gpg`, and OS keyrings.
128
+
129
+ ## Examples
130
+
131
+ By default the search runs against `INBOX` and returns the 10 most recent
132
+ matches as JSON. Pass `--mailbox <name>` to search elsewhere, `--limit N`
133
+ to widen or narrow the result count, and `--summary` for human-readable
134
+ output.
135
+
136
+ ```sh
137
+ # Unread mail, default INBOX, summary view
138
+ muttlike-imap "~U" --summary
139
+
140
+ # All mail from Alice in the last week
141
+ muttlike-imap "~f alice ~d <7d" --summary
142
+
143
+ # Archived correspondence with Bob about a specific topic
144
+ muttlike-imap '~L bob ~s "project x"' --mailbox Archive --summary
145
+
146
+ # Anything addressed to me, last 30 days, that I haven't replied to
147
+ muttlike-imap '~p ~d <30d !~Q' --summary
148
+
149
+ # Date range, ISO format
150
+ muttlike-imap '~d 2025-09-01-2025-12-31 ~f committee' --summary
151
+
152
+ # JSON for piping into jq
153
+ muttlike-imap "~U" | jq '.[] | {uid, subject, from}'
154
+
155
+ # Discover available folders
156
+ muttlike-imap --list-mailboxes
157
+ ```
158
+
159
+ ## Pattern syntax
160
+
161
+ `A B` is AND (juxtaposition), `A | B` is OR, `!A` is NOT, and `(...)` groups.
162
+
163
+ | Modifier | Meaning |
164
+ |----------|---------|
165
+ | `~f <text>` | From contains |
166
+ | `~t <text>` | To contains |
167
+ | `~s <text>` | Subject contains |
168
+ | `~b <text>` | Body contains |
169
+ | `~B <text>` | Body or any header contains |
170
+ | `~c <text>` | Cc contains |
171
+ | `~C <text>` | To, Cc, or Bcc contains |
172
+ | `~L <text>` | Any participant (From/To/Cc) |
173
+ | `~e <text>` | Sender header |
174
+ | `~i <text>` | Message-ID |
175
+ | `~y <text>` | X-Label |
176
+ | `~h "Name: text"` | Arbitrary header |
177
+ | `~x <text>` | References / In-Reply-To |
178
+ | `~A` | All messages |
179
+ | `~U` / `~N` | Unread / new |
180
+ | `~R` / `~O` | Read / old |
181
+ | `~F` | Flagged |
182
+ | `~D` | Deleted |
183
+ | `~Q` | Replied (answered) |
184
+ | `~p` | Addressed to you |
185
+ | `~P` | From you |
186
+ | `~d <Nu` | Date: header newer than N units (units `y m w d H M S`) |
187
+ | `~d >Nu` | Date: header older than N units |
188
+ | `~d =Nu` | Exactly N units old |
189
+ | `~d DATE` | On a specific date (`YYYY-MM-DD` or `D/M/Y`) |
190
+ | `~d -DATE` / `~d DATE-` | Half-open range (before / since) |
191
+ | `~d DATE-DATE` | Range |
192
+ | `~d DATE*Nu` | Range of ±N units around DATE |
193
+ | `~r DATERANGE` | Same grammar but on received date (INTERNALDATE) |
194
+ | `~z <N` / `~z >N` / `~z N-M` | Size in bytes (suffix `K`/`M`) |
195
+
196
+ See [`docs/pattern-syntax.md`](docs/pattern-syntax.md) for the full reference.
197
+
198
+ ### Limitations vs mutt
199
+
200
+ * **No regex.** IMAP `SEARCH` is substring-only, so all text matches are
201
+ literal. Anchors and character classes are not honored.
202
+ * **No mutt-runtime modifiers.** `~T` (tagged), `~v` (collapsed thread),
203
+ `~m` (message-number), `~n` (score), `~$`, `~#`, `~(...)` (thread patterns),
204
+ PGP modifiers: all error out instead of silently misbehaving.
205
+
206
+ `H`/`M`/`S` offsets are exact despite IMAP's day granularity: the server
207
+ narrows to the smallest whole-day window containing the precise range,
208
+ then a client-side post-filter trims the fetched candidates by their
209
+ `Date:` header (or `INTERNALDATE` for `~r`). `~d <30M` really does mean
210
+ "last 30 minutes". The post-filter is suppressed when the sub-day
211
+ modifier sits inside an `OR`, `!`, or paren-grouped disjunction, since
212
+ lifting its predicate to a top-level filter would change the pattern's
213
+ meaning.
214
+
215
+ ## Library use
216
+
217
+ ```python
218
+ from muttlike_imap.parser import parse_pattern
219
+ from muttlike_imap.client import search
220
+ from muttlike_imap.config import load_config
221
+
222
+ config = load_config() # or pass in your own dict
223
+ results = search(config, "~f alice ~U", limit=10, mailbox="INBOX")
224
+ for r in results:
225
+ print(r["subject"])
226
+
227
+ # Or just use the parser:
228
+ parse_pattern("(~f a | ~f b) ~U")
229
+ # → 'OR (FROM "a") (FROM "b") UNSEEN'
230
+ ```
231
+
232
+ ## License
233
+
234
+ MIT: see [LICENSE](LICENSE).