Skip to content

Repository files navigation

MML Documentation Matrix Mastodon

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 / forward commands bundling "template → $EDITOR → compile → validate/re-edit/view/abort", and interpret (aliased read) for the inverse MIME→MML flow.

Table of contents

Features

  • MML → MIME compilation (requires compiler feature):
    • <#part> / <#multipart> directives with type, 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 interpreter feature):
    • Header include / exclude filters
    • Part include / exclude filters
    • HTML → text rendering via nanohtml2text
    • Attachment save-to-disk
    • mml interpret (aliased mml read): MIME on stdin, MML/text on stdout
  • 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.

Installation

Pre-built binary

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 sh

As a regular user:

curl -sSL https://raw.githubusercontent.com/pimalaya/mml/master/install.sh | PREFIX=~/.local sh

For 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

cargo install mime-meta-language --locked --features cli

You 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.git

To use mml as a library, add it to your Cargo.toml:

[dependencies]
mime-meta-language = { version = "1.1", 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.

Nix

If you have the Flakes feature enabled:

nix profile install github:pimalaya/mml

Or run without installing:

nix run github:pimalaya/mml -- compile <<<'<#part>Hello, world!<#/part>'

Sources

git clone https://github.com/pimalaya/mml
cd mml
nix run

Configuration

A 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.

Usage

Library

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}");

CLI

Compile MML on stdin, emit MIME on stdout:

mml compile <<< '<#part>Hello, world!<#/part>'

Interpret MIME back to MML/text:

mml interpret < message.eml

Open the editor on a fresh compose draft, then emit the compiled MIME message on stdout, or to a file when a path is given:

mml compose --from me@example.org
mml compose --from me@example.org /tmp/draft.eml

Reply / forward read the source MIME on stdin (or from a path after --) and route the result the same way; the leading positional is the optional output path:

cat message.eml | mml reply --all
cat message.eml | mml forward /tmp/draft.eml
mml reply --all /tmp/draft.eml -- /tmp/source.eml

Pipelines into himalaya v2:

mml compose --from me@example.org /tmp/draft.eml && himalaya messages send /tmp/draft.eml
mml compose --from me@example.org >(himalaya messages send)
himalaya messages read 42 | mml reply >(himalaya messages send)

The path-arg or process-substitution forms keep mml's stdout connected to the terminal, so the editor mml spawns sees a real tty. The bare-pipe form mml compose | himalaya messages send hangs the editor because mml's stdout (and therefore the editor's inherited stdout) is the pipe to himalaya.

Read (MIME → text), useful for piping through less or chaining with himalaya:

cat message.eml | mml read --exclude-header Received,DKIM-Signature

Generate a draft template without opening the editor:

mml template compose --from me@example.org
mml template reply --all < message.eml
mml template forward < message.eml

Plug mml into himalaya v2 by wiring shell pipelines or aliases against the messages send / messages add / messages read primitives. A typical .bashrc snippet:

hsend() { local f=$(mktemp --suffix=.eml); mml compose "$f" && himalaya messages send "$f"; rm -f "$f"; }
hreply() { himalaya messages read "$1" | mml reply >(himalaya messages send); }

FAQ

How to debug the CLI?

Use --log <level> where <level> is one of off, error, warn, info, debug, trace:

mml --log trace compile < message.mml

The 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.log
How 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.

License

This project is licensed under either of:

at your option.

AI disclosure

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

Social

Sponsoring

nlnet

Special thanks to the NLnet foundation and the European Commission that have been financially supporting the project for years:

If you appreciate the project, feel free to donate using one of the following providers:

GitHub Ko-fi Buy Me a Coffee Liberapay thanks.dev PayPal

About

CLI and lib for the Emacs MIME message Meta Language (MML), written in Rust

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

Sponsor this project

Used by

Contributors

Languages