CLI and lib for the Emacs MIME message Meta Language (MML), written in Rust.
This repository ships two layers:
- Low-level library exposing two pipelines (MML→MIME compiler, MIME→MML interpreter) and a template builder for compose/reply/forward drafts.
- High-level CLI wrapping the library, plus editor-driven
compose/reply/forwardcommands bundling "template →$EDITOR→ compile → validate/re-edit/view/abort", andinterpret(aliasedread) for the inverse MIME→MML flow.
- MML → MIME compilation (requires
compilerfeature):<#part>/<#multipart>directives withtype,filename,disposition,encoding,description,name,recipient-filename, dates, etc.- Inline parts, attached parts, nested multiparts (
alternative,mixed,related) - File-path expansion via
shellexpand - MIME-type detection via
tree_magic_mini - Parse-error reporting via
ariadne(CLI)
- MIME → MML interpretation (requires
interpreterfeature):- Header include / exclude filters
- Part include / exclude filters
- HTML → text rendering via
nanohtml2text - Attachment save-to-disk
mml interpret(aliasedmml read): MIME on stdin, MML/text on stdout (himalayaread-withslot)
- Editor-driven flow (requires
cli+compiler+interpreter):mml compose/mml reply/mml forward: open$EDITOR, compile on save, prompt to validate / re-edit / view / abort
- TOML configuration with per-account identities and per-section defaults (
[compose],[reply],[forward],[read])
Tip
MML is written in Rust and uses cargo features to gate functionality. The default feature set is declared in Cargo.toml.
The CLI binary mml can be installed from the latest GitHub release using the install script:
As root:
curl -sSL https://raw.githubusercontent.com/pimalaya/mml/master/install.sh | sudo shAs a regular user:
curl -sSL https://raw.githubusercontent.com/pimalaya/mml/master/install.sh | PREFIX=~/.local shFor a more up-to-date version, check out the pre-releases GitHub workflow: pick the latest run and grab the artifact matching your OS. These are built from the master branch.
Note
Pre-built binaries are built with the default cargo features. If you need a different feature set, use another installation method.
cargo install mml --lockedYou can also use the git repository for a more up-to-date (but less stable) version:
cargo install --locked --git https://github.com/pimalaya/mml.gitTo use mml as a library, add it to your Cargo.toml:
[dependencies]
mml = { version = "1.0", default-features = false, features = ["compiler", "interpreter"] }Drop cli (and pick only compiler and/or interpreter) for a slim library build with no clap, no ariadne, no editor integration.
If you have the Flakes feature enabled:
nix profile install github:pimalaya/mmlOr run without installing:
nix run github:pimalaya/mml -- compile <<<'<#part>Hello, world!<#/part>'git clone https://github.com/pimalaya/mml
cd mml
nix runA sample config.sample.toml is shipped at the repository root. Drop it into one of:
$XDG_CONFIG_HOME/mml/config.toml$HOME/.config/mml/config.toml$HOME/.mmlrc
Override the path with -c <PATH> or MML_CONFIG=<PATH>.
CLI flags always win; config values fill in the blanks. Pick an account with -a <NAME>, or flag one entry default = true.
Compile MML to MIME:
use mml::compiler::message::MmlCompilerBuilder;
let mml = "<#part>Hello, world!<#/part>";
let mime = MmlCompilerBuilder::new()
.build(mml)?
.compile()?
.into_string()?;
println!("{mime}");Interpret MIME back to MML:
use mml::interpreter::message::MimeInterpreterBuilder;
let mime = b"From: a@b\r\nTo: c@d\r\nSubject: Hi\r\n\r\nHello!\r\n";
let mml = MimeInterpreterBuilder::new()
.with_show_only_headers(["From", "To", "Subject"])
.build()
.from_bytes(mime)?;
println!("{mml}");Compile MML on stdin, emit MIME on stdout:
mml compile <<< '<#part>Hello, world!<#/part>'Interpret MIME back to MML/text:
mml interpret < message.emlOpen the editor on a fresh compose draft, then emit the compiled MIME message on stdout:
mml compose --from me@example.orgReply / forward from a piped MIME message:
cat message.eml | mml reply --all
cat message.eml | mml forwardRead (MIME → text) for himalaya's read-with:
cat message.eml | mml read --exclude-header Received,DKIM-SignatureGenerate a draft template without opening the editor:
mml template compose --from me@example.org
mml template reply --all < message.eml
mml template forward < message.emlPlug mml into himalaya v2:
[message.composer.mml]
command = "mml compose"
default = true
[message.reader.mml]
command = "mml read"
default = trueHow to debug the CLI?
Use --log <level> where <level> is one of off, error, warn, info, debug, trace:
mml --log trace compile < message.mmlThe RUST_LOG environment variable, when set, overrides --log and supports per-target filters (see the env_logger documentation). RUST_BACKTRACE=1 enables full error backtraces, including source lines where the error originated from.
Logs are written to stderr, so they can be redirected easily to a file:
mml --log trace compile < message.mml 2>/tmp/mml.logHow does `mml compose` pick the editor?
The edit crate resolves $VISUAL first, then $EDITOR, then an OS default. mml does not expose a config knob on top: set VISUAL / EDITOR in your shell rc file.
This project is licensed under either of:
at your option.
This project is developed with AI assistance. This section documents how, so users and downstream packagers can make informed decisions.
-
Tools: Claude Code (Anthropic), Opus 4.7, invoked locally with a persistent project-scoped memory and a small set of repo-specific rules.
-
Used for: Refactors, mechanical multi-file edits, boilerplate (feature gates, error enums, derive macros, trait impls), test scaffolding, doc polish, exploratory design conversations.
-
Not used for: Engineering, critical code, git manipulation (commit, merge, rebase…), real-world tests.
-
Verification: Every AI-assisted change is read, compiled, tested, and formatted before commit (
nix develop --command cargo check / cargo test / cargo fmt). Behavioural correctness is verified against the relevant RFC or upstream spec, not assumed from the model output. Tests are never adjusted to fit AI-generated code; the code is adjusted to fit correct behaviour. -
Limitations: AI models occasionally produce code that compiles and passes tests but is subtly wrong: off-by-one errors, missed edge cases, plausible but nonexistent APIs, stale RFC references. The verification workflow catches most of this; it does not catch all of it. Bug reports are welcome and taken seriously.
-
Last reviewed: 31/05/2026
- Chat on Matrix
- News on Mastodon or RSS
- Mail at pimalaya.org@posteo.net
Special thanks to the NLnet foundation and the European Commission that have been financially supporting the project for years:
- 2022 → 2023: NGI Assure
- 2023 → 2024: NGI Zero Entrust
- 2024 → 2026: NGI Zero Core
- 2027 in preparation…
If you appreciate the project, feel free to donate using one of the following providers:
