Skip to main content

Search IMAP mailboxes from the command line using mutt-style patterns.

Project description

muttlike-imap

CI PyPI License: MIT

Search IMAP mailboxes from the command line using mutt-style patterns.

$ muttlike-imap "~f alice ~U" --summary
1 result(s):

UID:1264 | From:Alice <alice@example.com> | Date:Tue, 21 Apr 2026 15:02:35 +0000
Subject:Re: project update
Preview:Hi, here is the latest version of the document…

Why

Mutt has a great pattern language for finding messages (~f, ~s, ~d <7d, !~U, (A | B) C, …). IMAP servers can do most of the same searches, but the wire protocol is verbose and the bindings in imaplib are awkward to compose. muttlike-imap is a small CLI that translates mutt patterns into IMAP SEARCH criteria and prints the matches as JSON or a human-readable summary.

It's intentionally small and scriptable – useful as a building block for notification scripts, AI assistants, cron jobs, or one-off lookups.

Install

pip install muttlike-imap

Requires Python 3.9+. No third-party dependencies.

Shell completion

muttlike-imap ships completion scripts for zsh, bash, and fish. Add one of the following to your shell rc file:

# zsh (~/.zshrc)
eval "$(muttlike-imap --completion zsh)"

# bash (~/.bashrc)
eval "$(muttlike-imap --completion bash)"

# fish (~/.config/fish/config.fish, or just save the output)
muttlike-imap --completion fish | source

The zsh script offers per-flag tailoring (file paths for --config, (true false) for --imap-tls, env-var names for --imap-password-env, live mailbox completion via --list-mailboxes). Bash and fish provide flag-name completion plus the same enumerations where applicable.

Configure

muttlike-imap looks for connection settings in this order (highest priority first):

  1. CLI flags: --imap-host, --imap-port, --imap-user, --imap-password-cmd, --imap-password-env, --imap-tls.
  2. Environment variables: IMAPQUERY_HOST, IMAPQUERY_PORT, IMAPQUERY_USER, IMAPQUERY_PASS, IMAPQUERY_TLS.
  3. The file pointed to by $IMAPQUERY_CONFIG, if set.
  4. $XDG_CONFIG_HOME/muttlike-imap/config (defaults to ~/.config/muttlike-imap/config).
  5. ~/.config/imap-smtp-email/.env: kept as a fallback for users who already have this file from the openclaw imap-smtp-email skill. See docs/openclaw.md for wiring muttlike-imap into an openclaw workspace.

A minimal config file:

IMAP_HOST=imap.example.com
IMAP_PORT=993
IMAP_USER=you@example.com
IMAP_PASS_CMD=pass email/imap.example.com
IMAP_TLS=true

The keys can be written with the IMAP_ prefix (shown above, matches mutt and offlineimap conventions), with the IMAPQUERY_ prefix, or with no prefix at all (HOST=…); pick whichever you prefer.

Passwords

There are three ways to give muttlike-imap your password, in increasing order of how much they leak:

  • IMAP_PASS_CMD=<shell command> (recommended). The command is run on every invocation; the first line of stdout is used as the password. Pair with pass, secret-tool, macOS Keychain (security find-generic-password -w), or anything else that prints a secret to stdout. The password lives only in the muttlike-imap process memory and is never written to disk or to the environment.

    Equivalent CLI flag: --imap-password-cmd "pass email/imap.example.com".

  • --imap-password-env MY_VAR. Reads the password from a named environment variable. Useful when you already have a secret in a variable (e.g. via direnv or a parent process) and don't want to re-export it. Caveat: env vars leak through /proc/<pid>/environ, child processes, ps eww, and crash dumps.

  • IMAP_PASS=<plaintext> in the config file. Simplest, least secure; fine for throwaway accounts and local-only setups. Make sure the file is chmod 600.

See docs/secrets.md for worked examples with pass, raw gpg, and OS keyrings.

Examples

By default the search runs against INBOX and returns the 10 most recent matches as JSON. Pass --mailbox <name> to search elsewhere, --limit N to widen or narrow the result count, and --summary for human-readable output.

# Unread mail, default INBOX, summary view
muttlike-imap "~U" --summary

# All mail from Alice in the last week
muttlike-imap "~f alice ~d <7d" --summary

# Archived correspondence with Bob about a specific topic
muttlike-imap '~L bob ~s "project x"' --mailbox Archive --summary

# Anything addressed to me, last 30 days, that I haven't replied to
muttlike-imap '~p ~d <30d !~Q' --summary

# Date range, ISO format
muttlike-imap '~d 2025-09-01-2025-12-31 ~f committee' --summary

# JSON for piping into jq
muttlike-imap "~U" | jq '.[] | {uid, subject, from}'

# Discover available folders
muttlike-imap --list-mailboxes

Pattern syntax

A B is AND (juxtaposition), A | B is OR, !A is NOT, and (...) groups.

Modifier Meaning
~f <text> From contains
~t <text> To contains
~s <text> Subject contains
~b <text> Body contains
~B <text> Body or any header contains
~c <text> Cc contains
~C <text> To, Cc, or Bcc contains
~L <text> Any participant (From/To/Cc)
~e <text> Sender header
~i <text> Message-ID
~y <text> X-Label
~h "Name: text" Arbitrary header
~x <text> References / In-Reply-To
~A All messages
~U / ~N Unread / new
~R / ~O Read / old
~F Flagged
~D Deleted
~Q Replied (answered)
~p Addressed to you
~P From you
~d <Nu Date: header newer than N units (units y m w d H M S)
~d >Nu Date: header older than N units
~d =Nu Exactly N units old
~d DATE On a specific date (YYYY-MM-DD or D/M/Y)
~d -DATE / ~d DATE- Half-open range (before / since)
~d DATE-DATE Range
~d DATE*Nu Range of ±N units around DATE
~r DATERANGE Same grammar but on received date (INTERNALDATE)
~z <N / ~z >N / ~z N-M Size in bytes (suffix K/M)

See docs/pattern-syntax.md for the full reference.

Limitations vs mutt

  • No regex. IMAP SEARCH is substring-only, so all text matches are literal. Anchors and character classes are not honored.
  • No mutt-runtime modifiers. ~T (tagged), ~v (collapsed thread), ~m (message-number), ~n (score), ~$, ~#, ~(...) (thread patterns), PGP modifiers: all error out instead of silently misbehaving.

H/M/S offsets are exact despite IMAP's day granularity: the server narrows to the smallest whole-day window containing the precise range, then a client-side post-filter trims the fetched candidates by their Date: header (or INTERNALDATE for ~r). ~d <30M really does mean "last 30 minutes". The post-filter is suppressed when the sub-day modifier sits inside an OR, !, or paren-grouped disjunction, since lifting its predicate to a top-level filter would change the pattern's meaning.

Library use

from muttlike_imap.parser import parse_pattern
from muttlike_imap.client import search
from muttlike_imap.config import load_config

config = load_config()  # or pass in your own dict
results = search(config, "~f alice ~U", limit=10, mailbox="INBOX")
for r in results:
    print(r["subject"])

# Or just use the parser:
parse_pattern("(~f a | ~f b) ~U")
# → 'OR (FROM "a") (FROM "b") UNSEEN'

License

MIT: see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

muttlike_imap-1.1.0.tar.gz (43.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

muttlike_imap-1.1.0-py3-none-any.whl (24.9 kB view details)

Uploaded Python 3

File details

Details for the file muttlike_imap-1.1.0.tar.gz.

File metadata

  • Download URL: muttlike_imap-1.1.0.tar.gz
  • Upload date:
  • Size: 43.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for muttlike_imap-1.1.0.tar.gz
Algorithm Hash digest
SHA256 86438f209306dd731895d79c23a911a88c3e71ebbfe0529d62859c258852ba1e
MD5 0390bbed8ae4b4b1f996bf960d3a87b4
BLAKE2b-256 8bf236f6ef25835c17a7cbe52860277a79946ed3a63e9eb5089956d95f12912b

See more details on using hashes here.

Provenance

The following attestation bundles were made for muttlike_imap-1.1.0.tar.gz:

Publisher: release.yml on PierreSenellart/muttlike-imap

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file muttlike_imap-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: muttlike_imap-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 24.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for muttlike_imap-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e36b3fdf84288504e2460579250dd7a11f86d05741fb04ef8a16f83f2be86dc1
MD5 55d5849c2a0848ef8961b92e5fa90b59
BLAKE2b-256 09b25186e019fa0afa53b8a87317cfd7322d66d1d55eb83ee7d1881642be0eee

See more details on using hashes here.

Provenance

The following attestation bundles were made for muttlike_imap-1.1.0-py3-none-any.whl:

Publisher: release.yml on PierreSenellart/muttlike-imap

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page