id = "mail-deduplicate" name = "Mail Deduplicate" homepage = "https://kdeldycke.github.io/mail-deduplicate/" description = "Remove duplicate emails from your mailboxes." executables = ["mdedup"] [dotfiles] # https://kdeldycke.github.io/mail-deduplicate/configuration.html — the # documentation names the platform-native mdedup config directory on macOS # and Windows, and ~/.config/mdedup on Unix. These are the two catalog roots # for the same user configuration directory; no credential fields are # documented in this configuration. paths = ["[appData]/mdedup/", "[configHome]/mdedup/"] secret = [] [commands] format = 1 label = "Deduplicate mailboxes" description = "Find duplicate mails across one or more mailboxes, pick which copy to keep with a strategy, then act on the result. The default action only copies the selection to a new box. Hash tuning, thresholds and the regexp-based strategies are left out." quality = "ai-draft" parser = { end_of_options = "--", interleave = "permute", long_equals = true, short_attached = true, short_bundles = false } [[commands.source]] id = "help" kind = "help" url = "https://kdeldycke.github.io/mail-deduplicate/cli.html" revision = "2026-10-27" evidence = """ Usage: mdedup [OPTIONS] MAIL_SOURCE_1 MAIL_SOURCE_2 ... -i, --input-format [maildir|mbox|mh|babyl|mmdf|eml] -b, --hash-body [skip|raw|normalized] --cache / --no-cache -s, --strategy [select-older|select-oldest|select-newer|select-newest|discard-newest|discard-newer|discard-oldest|discard-older|select-smaller|select-smallest|select-bigger|select-biggest|discard-biggest|discard-bigger|discard-smallest|discard-smaller|select-matching-path|select-non-matching-path|discard-non-matching-path|discard-matching-path|select-one|select-all-but-one|discard-all-but-one|discard-one] -a, --action [copy-selected|copy-discarded|move-selected|move-discarded|delete-selected|delete-discarded|hardlink-discarded] -E, --export MAIL_BOX_PATH -e, --export-format [maildir|mbox|mh|babyl|mmdf|eml] --export-append -n, --dry-run -H, --hash-only """ [[commands.field]] id = "sources" label = "Mail sources" description = "Mailboxes (maildir, mbox, ...) or mail files to deduplicate." type = "path" path = { kind = "any", role = "input" } position = 0 multiple = true min = 1 sources = ["help"] [[commands.field]] id = "strategy" label = "Selection strategy" description = "Which copy of each duplicate set is selected. Without one, nothing is selected and no action is taken." type = "string" option = ["--strategy", "-s"] suggestions = [{ value = "select-oldest", label = "Select oldest" }, { value = "select-newest", label = "Select newest" }, { value = "select-biggest", label = "Select biggest" }, { value = "select-smallest", label = "Select smallest" }, { value = "select-one", label = "Select one copy" }, { value = "select-all-but-one", label = "Select all but one" }] sources = ["help"] [[commands.field]] id = "action" label = "Action" description = "Default copy-selected only reads the sources and writes a new box. The delete-* and move-* actions change the sources; rehearse with Dry run." type = "enum" option = ["--action", "-a"] choices = [{ value = "copy-selected", label = "Copy selected" }, { value = "copy-discarded", label = "Copy discarded" }, { value = "move-selected", label = "Move selected" }, { value = "move-discarded", label = "Move discarded" }, { value = "delete-selected", label = "Delete selected" }, { value = "delete-discarded", label = "Delete discarded" }, { value = "hardlink-discarded", label = "Hardlink discarded" }] sources = ["help"] [[commands.field]] id = "export" label = "Destination mailbox" description = "Required by the copy and move actions." type = "path" option = ["--export", "-E"] path = { kind = "any", role = "output", must_exist = false } effect = "overwrite" sources = ["help"] [[commands.field]] id = "export_format" label = "Destination format" type = "enum" option = ["--export-format", "-e"] choices = [{ value = "maildir", label = "Maildir" }, { value = "mbox", label = "mbox" }, { value = "mh", label = "MH" }, { value = "babyl", label = "Babyl" }, { value = "mmdf", label = "MMDF" }, { value = "eml", label = "eml files" }] observed_default = "mbox" sources = ["help"] [[commands.field]] id = "export_append" label = "Append to existing destination" type = "boolean" option = ["--export-append"] sources = ["help"] [[commands.field]] id = "input_format" label = "Force input format" description = "Leave unset to auto-detect maildir, mbox and eml." type = "enum" option = ["--input-format", "-i"] choices = [{ value = "maildir", label = "Maildir" }, { value = "mbox", label = "mbox" }, { value = "mh", label = "MH" }, { value = "babyl", label = "Babyl" }, { value = "mmdf", label = "MMDF" }, { value = "eml", label = "eml files" }] sources = ["help"] [[commands.field]] id = "hash_body" label = "Hash mail bodies" type = "enum" option = ["--hash-body", "-b"] choices = [{ value = "skip", label = "Skip (headers only)" }, { value = "raw", label = "Raw" }, { value = "normalized", label = "Normalized" }] observed_default = "skip" sources = ["help"] [[commands.field]] id = "cache" label = "Reuse hash cache" type = "boolean" option = ["--cache"] false_option = "--no-cache" sources = ["help"] [[commands.field]] id = "dry_run" label = "Dry run" description = "Report what would be done without doing it." type = "boolean" option = ["--dry-run", "-n"] sources = ["help"] [[commands.task]] id = "merge" label = "Merge into a new mailbox" fields = ["sources", "strategy", "export", "dry_run"] required = ["sources", "strategy", "export"] set = { strategy = ["select-one"] } [[commands.task]] id = "rehearse_delete" label = "Rehearse deleting duplicates" fields = ["sources", "strategy", "action", "dry_run"] required = ["sources", "strategy", "action", "dry_run"] set = { strategy = ["select-one"], action = ["delete-discarded"], dry_run = [true] } [[commands.group]] id = "basic" label = "Basic" fields = ["sources", "strategy", "action", "export", "dry_run"] [[commands.group]] id = "advanced" label = "Advanced" fields = ["export_format", "export_append", "input_format", "hash_body", "cache"]