armindarvish / consult-mu

Consult Mu4e asynchronously in GNU Emacs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

consult-mu - use consult to search mu4e dynamically or asynchronously

Armin Darvish GNU Emacs

About consult-mu

Consult-mu provides a dynamically updated search interface to mu4e. It uses the awesome package consult by Daniel Mendler and mu/mu4e by Dirk-Jan C. Binnema, and optionally Embark by Omar Antolín Camarena to improve the search experience of mu4e.

Main Interactive Commands

There two main interactive commands:

  1. consult-mu-dynamic: Provides a dynamic version of mu4e-search. As the user types inputs, the result gets updated. This command uses a modified version of mu4e-search and then takes the content of mu4e-headers buffer to populate minibuffer completion table. This allows the user to change the query or search properties (such as number of results, sort-field, sort-direction, …) dynamically by changing the input in the minibuffer. In addition previews of the results can be viewed similar to other consult functions. Once a candidate is selected, the user will see the search result sin mu4e-headers, and mu4e-view buffers similar to mu4e-search results.
  2. consult-mu-async: This function provides a very fast search without loading mu4e-headers, which means mu4e functionalities (like marks, reply, forwards, etc.) are not available in the preview buffer. This is very useful for finding individual emails or threads in a large pool quickly (in other words “a needle in a haystack” scenarios!). Previews can be seen while the results are being populated asynchronously (without populating mu4e-headers buffer). Upon selection of a candidate, mu4e-headers buffer is populated with only an individual email (or thread). From here all the normal functionalities of mu4e is again available.
  3. consult-mu: This is simply a wrapper that calls consult-mu-default-command, which can be set to either the dynamic or async command for quick access. In other words, set consult-mu-default-command to either 1 or 2 above depending on your use case and then use consult-mu for convinience and you don’t need to remember the difference between the two anymore.

The advantage of consult-mu-async over consult-mu-dynamic is that it is very fast for searching several thousands of messages (even faster than consult-notmuch!), but cannot populate a mu4e-headers buffer with all the results. On the other hand, consult-mu-dynamic is slower when there are thousands of hits for the search term but provides full functionality for all the results (provides full functionality of mu4e-search). Therefore, depending on the use case, the user can chose which functions serves the purpose better.

Furthermore, consult-mu, also provides a number of useful Embark actions that can be called from within minibuffer (see examples below). However, when using embark actions, be advised that sometimes you may get an error especially when using consult-mu-async. These are likely not critical errors hapening when the databse is out of sync with the results. In such cases syncing the database should resolve the issue.

Getting Started

Installation

Before you start, make sure you understand that this is work in progress in its early stage and bugs and breaks are very much expected.

note that: Because mu4e tends to take over buffer/windows management, I had to reimplement (a.k.a. hack) some of the functionalities in order to provide quick previews that stay out of your way when the minibuffer command is done (or canceled), and as a result there is a good chance that errors will arise in edge cases that I have not tested.

Requirements

In order to use consult-mu, you need the following requirements:

You can access the official documentation for mu4e here: mu4e official manual. If you need step-by-step instructions or prefer videos, there are many useful tutorials online. Here are a few good links:

To install consult follow the official instructions here: Configuration of Consult.

Also, make sure you review Consult’s README since it recommends some other packages and useful configurations for different settings. Some of those may improve your experience of consult-mu as well. In particular, the section about asynchronous search is important for learning how to use inputs to search for result and narrow down in minibuffer.

Installing consult-mu package

consult-mu is not currently on ELPA or MELPA. Therefore, you need to install it using an alternative non-standard package manager such as straight.el or use manual installation.

straight.el

To install consult-mu with straight.el you can use the following command. Make sure you load consult-mu after loading mu4e and consult (e.g. require consult, require mu4e).

(straight-use-package
 '(consult-mu :type git :host github :repo "armindarvish/consult-mu" :branch "main" :files (:defaults "extras/*.el")))

or if you use use-package macro with straight, you can do:

(use-package consult-mu
	:straight (consult-mu :type git :host github :repo "armindarvish/consult-mu" :files (:defaults "extras/*.el"))
        :after (mu4e consult)
)

You can also fork this repository and use your own repo.

manual installation

Clone this repo and make sure the files are on your load path, as described on EmacsWiki.

Make sure you load consult and mu4e (e.g. require consult, require mu4e) before you load consult-mu.

Configuration

consult-mu is built with the idea that the user should be able to customize everything based on their use-case, therefore the user is very much expected to configure consult-mu.

I recommend you read through this section and understand how to configure the package according to your needs and for your specific use-case, but if you just want a drop-in minimal config, look at the snippet below (for snippet with extended settings see extended feature config).

Minimal Config

(use-package consult-mu
  :straight (consult-mu :type git :host github :repo "armindarvish/consult-mu" :branch "main")
  :after (consult mu4e)
  :custom
  ;;maximum number of results shown in minibuffer
  (consult-mu-maxnum 200)
  ;;show preview when pressing any keys
  (consult-mu-preview-key 'any)
  ;;do not mark email as read when previewed
  (consult-mu-mark-previewed-as-read nil)
  ;;do not amrk email as read when selected. This is a good starting point to ensure you would not miss important emails marked as read by mistake especially when trying this package out. Later you can change this to t.
  (consult-mu-mark-viewed-as-read nil)
  ;; open the message in mu4e-view-buffer when selected.
  (consult-mu-action #'consult-mu--view-action)
  )

Extended Feature Config

Here is a customization that gives you the full feature experience including utilities for attaching/detaching files and searching contacts, etc.

(use-package consult-mu
  :straight (consult-mu :type git :host github :repo "armindarvish/consult-mu" :branch "develop" :files (:defaults "extras/*.el"))
  :after (consult mu4e)
  :custom
  ;;maximum number of results shown in minibuffer
  (consult-mu-maxnum 200)
  ;;show preview when pressing any keys
  (consult-mu-preview-key 'any)
  ;;do not mark email as read when previewed. If you turn this to t, be aware that the auto-loaded preview if the preview-key above is 'any would also get marked as read!
  (consult-mu-mark-previewed-as-read nil)
  ;;mark email as read when selected.
  (consult-mu-mark-viewed-as-read t)
  ;;use reply to all when composing reply emails
  (consult-mu-use-wide-reply t)
  ;; define a template for headers view in minibuffer. The example below adjusts the width based on the width of the screen.
  (consult-mu-headers-template (lambda () (concat "%f" (number-to-string (floor (* (frame-width) 0.15))) "%s" (number-to-string (floor (* (frame-width) 0.5))) "%d13" "%g" "%x")))

  :config
  ;;create a list of saved searches for quick access using `histroy-next-element' with `M-n' in minibuffer. Note the "#" character at the beginning of each query! Change these according to
  (setq consult-mu-saved-searches-dynamics '("#flag:unread"))
  (setq consult-mu-saved-searches-async '("#flag:unread"))
  ;; require embark actions for marking, replying, forwarding, etc. directly from minibuffer
  (require 'consult-mu-embark)
  ;; require extra module for composing (e.g. for interactive attachment) as well as embark actions
  (require 'consult-mu-compose)
  (require 'consult-mu-compose-embark)
  ;; require extra module for searching contacts and runing embark actions on contacts
  (require 'consult-mu-contacts)
  (require 'consult-mu-contacts-embark)
  ;; change the prefiew key for compose so you don't open a preview of every file when selecting files to attach
  (setq consult-mu-compose-preview-key "M-o")
  ;; pick a key to bind to consult-mu-compose-attach in embark-file-map
  (setq consult-mu-embark-attach-file-key "C-a")
  (setq consult-mu-contacts-ignore-list '("^.*no.*reply.*"))
  (setq consult-mu-contacts-ignore-case-fold-search t)
  (consult-mu-compose-embark-bind-attach-file-key)
  ;; choose if you want to use dired for attaching files (choice of 'always, 'in-dired, or nil)
  (setq consult-mu-compose-use-dired-attachment 'in-dired)
  )

Customization Variables

The following customizable variables are provided:

main

consult-mu-default-command

A command function that is called when M-x consult-mu is called. This is useful for defining special conditions to use consult-mu-dynamics or consult-mu-async. By default it is bound to consult-mu-dynamics, therefore M-x consult-mu simply calls consult-mu-dynamics.

consult-mu-headers-buffer-name

This is the default name for HEADERS buffer explicitly for consult-mu. It is, by default, set to =”**consult-mu-headers**”=. Note that currently, the header-buffer name is a constant string and shared between all instances of consult-mu calls. This is to prevent running operations in parallel that cause out-of-sync issues.

consult-mu-view-buffer-name

This is the default name for VIEW buffer explicitly for consult-mu. It is, by default, set to =”**consult-mu-view**”=. Note that currently, the view-buffer name is a constant string and shared between all instances of consult-mu calls. This is to prevent creating too many preview buffers and executing operations (such as marking) in parallel that cause out-of-sync issues.

consult-mu-args

This is the default name of the mu command line argument. It is set to =”mu”= by default, but can be modified for example if mu is at a different path on your system.

consult-mu-maxnum

Maximum number of messages shown in search results (in consult-mu minibuffer completion table). This is a global option for consult-mu and consult-mu-async, but can be overriden by providing command line arguments in input for example, the following search would fetch up to 1000 results

#github -- --maxnum 1000
consult-mu-headers-fields

This variable is used to format the headers inside minibuffer. This takes a similar format to mu4e-headers-fields and changes the format of the header only in minibuffer (consult-mu-dynamic or consult-mu-async).

Note that it is generally recommended to use consult-mu-headers-template below because it has more options and does not affect the consult-mu-headers buffer.

consult-mu-headers-template
This is a template string that overrides the consult-mu-headers-field to format headers. It provides more options than consult-mu-headers-field and is generally the recommended approach to make custom headers. Special chaacters in the string (either “%[char]” or “%[char][integer]”) in the string get expanded to create headers. Each character represents a different field and the integer defines the length of the field. For exmaple “%d15%s50” means 15 characters for date and 50 charcters for subject.

The list of available fields are:

%f sender(s) (e.g. from: field of email) %t receivers(s) (i.e. to: field of email) %s subject (i.e. title of email) %d date (i.e. the date email was sent/received) with the format “Thu 09 Nov 23” %p priority %z size %i message-id (as defined by mu) %g flags (as defined by mu) %G pretty flags (this uses mu4e~headers-flags-str to pretify flags) %x tags (as defined by mu) %c cc (i.e. cc: field of the email) %h bcc (i.e. bcc: field of the email) %r date chaged (as defined by :changed in mu4e)

For example, the string =”%d13%s50%f17%G”= would make a header containing 13 characters for date, 50 characters for subject, and 20 characters for from field, making headers that looks like this:

https://github.com/armindarvish/consult-mu/blob/screenshots/screenshots/consult-mu-headers-template.png

consult-mu-search-sort-field

This defines the field that is used for sorting the results (refer to documentation on the variable mu4e-search-sort-field for more info). It has to be one of the keywords:

  • :date sort by date
  • :subject sort by title of the email
  • :size sort by file size
  • :prio sort by priority
  • :from sort by name/email of the sender(s)
  • :to sort by name/email of receivers
  • :list sort by mailing list

Note that the sort field can dynamically be changed by providing command line arguments in the minibuffer input.

For example the following input in the minibuffer will search for emails that are flagged unread but then overrides the sort field and change it t subject. For details on how to use command line arguments refer to mu manual (e.g. by running mu find --help in the command line)

#flag:unread -- -s s
consult-mu-search-sort-direction

Direction of sort. It can either be =’ascending= for A->Z (low number to high number) or =’descending= for Z->A (high number to low number). Note that if a command line argument for reverse order (either -z or –reverse) is provided in the minibuffer, the order will be reverse of the setting defined by this variable.

For example, if consult-mu-search-sort-field is set to :date and consult-mu-search-sort-direction is set to =’descending= the messages are sortes chronologically from the newest on top to the oldest. Then providing a reverse order argument in the minibuffer can dynamically reverse the sort direction:

For example the following input in the minibuffer searches for all unread emails under =”./inbox”= path then reverses the sort direction (because of -z command line argument)

#(maildir:/inbox) AND flag:unread -- -z
consult-mu-search-threads

This variable determines whether threads are calculated for search results or not similar to the mu4e-search-threads variable.

Note that per mu4e docs: When threading is enabled, the headers are exclusively sorted chronologically (:date) by the newest message in the thread.

When this variable is set to nil, it can still be truned on by adding command line arguments (i.e. -t or --thread) in the input. For example the following input in the minibuffer will ensure that threads are on even if consult-mu-search-threads is set to nil.

#flag:unread -- -t
consult-mu-group-by

This variable determines what field is used to group messages. This aloows quick movement between groups (For example with vertico-next-group if you use vertico)

By default it is set to :date. But can be any of the following keywords:

  • :subject group by mail title
  • :from group by name/email of the sender(s)
  • :to group by name/email of the receiver(s)
  • :date group by date in the format “Thu 09 Nov 23”
  • :time group by the time of email in the format “20:30:07”
  • :datetime group by date and time of the email with the format “2023-11-04 08:30:07 PM”
  • :year group by the year of the email (i.e. 2023, 2022, …)
  • :month group by the month of the email (i.e. Jan, Feb, …, Dec)
  • :week group by the week number of the email (.i.e. 1, 2, 3, …, 52)
  • :day-of-week group by the day email was sent (i.e. Monday, Tuesday, …)
  • :size group by the file size of the email
  • :flags group by flags (as defined by mu)
  • :tags group by tags (as defined by mu)
  • :changed group by the date changed (as defined by :changed field in mu4e)

Note that grouping works alongside sorting. For example if consult-mu-group-by is set to :day-of-week and consult-mu-search-sort-field is set to :date, then the messages are grouped by day of week (e.g. all emails on Tuesdays will be in one group) then ordered chronologically within each group. The screenshot below shows some examples:

https://github.com/armindarvish/consult-mu/blob/screenshots/screenshots/consult-mu-grouping-example.png

consult-mu-mark-previewed-as-read

This determines whether a message is marked as read when it is simply previewed (see consult-mu-preview-key above and documentation on consult-preview-key).

Note that when consult-mu-preview-key is set to =’any=, then as soon as consult-mu or consult-mu-async retrieve some results a preview for the first message is shown and this can be marked as read if consult-mu-mark-previewed-as-read is set to t.

consult-mu-mark-viewed-as-read

This determines whether a message is marked as read when it is viewed (i.e. when the minibuffer candidate is selected by hitting RET).

consult-mu-preview-key

This is similar to consult-preview-key but only for consult-mu. By default, it is set to the value of consult-preview-key to keep consistent experience across different consult packages, but you can set this variable explicitly for consult-mu.

The recommended option is to set this to =’any= so as you naviagte over the candidates you see previews updated.

(setq consult-mu-preview-key 'any)

If the option above slows down your system, and you only want to load previews on demand, then you can set it to a specific key such as =”M-o”=.

(setq consult-mu-preview-key "M-o")

You can also turn previews off by setting this variable to nil, but this is not generally recommended.

consult-mu-highlight-matches

This variable determines if consult-mu highlights search queries in minibuffer or preview buffers. By default it is set to t.

When it is set to t, all matches of the search term are highlighted in the minibuffer allowing you to notice why the email is a search hit.

For example in the screenshot below, I am searching for the term consult and all the matches of consult are highlighted in the titles.

https://github.com/armindarvish/consult-mu/blob/screenshots/screenshots/consult-mu-highlight-matches-minibuffer.png

Furthermore if I look at a preview, all the instances of consult-gh matches in the preview buffer are also highlighted:

https://github.com/armindarvish/consult-mu/blob/screenshots/screenshots/consult-mu-highlight-matches-preview.png

Note that when the candidate is selected (i.e. by pressing RET), the highlight overlay is turned off, so you can see the orignial message as is, but you can call consult-mu-overlays-toggle (i.e. M-x consult-mu-overlays-toggle) to see the highlights of the query again.

https://github.com/armindarvish/consult-mu/blob/screenshots/screenshots/consult-mu-highlight-matches-view.png

consult-mu-action

This variable stores the function that is called when a message is selected (i.e. RET is pressed in the minibuffer). By default it is bound to consult-mu--view-action which opens both the headers buffer and view buffer and shows the content of the selected message.

compose

These variables are only available after loading the compose module;

(require 'consult-mu-compose)
consult-mu-compose-use-dired-attachment

This variable defines, whether consult-mu uses dired buffers for selecting files to attach. If it is set to =’always=, consult-mu will always jump to a dired buffer for selecting files to attach. It it is set to =’in-dired=, consult-mu only uses dired (a.k.a. file at point or marked files) for attaching files when already inside a dired buffer. If it is set to nil, consult-mu uses minibuffer completion for file selection for attachments.

consult-mu-large-file-warning-threshold

A threshold to make sure very large files are not accidentally opened when previewing files that the user wants to attach to an email. If file is larger than this threshold, the user is asked to confirm before loading the file buffer.

consult-mu-compose-preview-key

This is similar to consult-mu-preview-key but only for consult-mu-compose. This is used to preview files when selecting files for attachments. By default, it is set to the follow the value of consult-mu-preview-key to keep consistent experience across the package. *But it is recommended to change this to something other than =’any= becuase otherweise every file is previewd as the user is navigating through folders to select files to attach to an email.

(setq consult-mu-compose-preview-key "M-o")
consult-mu-embark-attach-file-key

This variable defines a key that can be bound to consult-mu-compose-attach in emabrk-file-map, therefore one can call embark on any file and use this key to attach it to an email. This can be bound to “a” or “C-a”:

(setq consult-mu-embark-attach-file-key "C-a")

Running the function consult-mu-compose-embark-bind-attach-file-key binds this key, but any other key can be passed to this function as well to override the customization variable:

(consult-mu-compose-embark-bind-attach-file-key)

contacts

These variables are only available after loading the contacts module;

(require 'consult-mu-contacts)
consult-mu-contacts-group-by

This variable determines what field is used to group contacts, which allows quick movement between groups (For example with vertico-next-group if you use vertico)

By default it is set to name. But can be any of the following keywords:

  • :name group by contact name
  • :email group by email of the contact
  • :domain group by the domain of the contact’s email (e.g. domain.com in user@domain.com)
  • :user group by the ncontact’s user name (e.g. user in user@domain.com)

For example if consult-mu-contacts-group-by is set to :domain then the domain of the email address is used to group contacts. This is useful for example if you are looking for all emails from a specific company!

consult-mu-contacts-action

This variable stores the function that is called when a contact is selected (i.e. RET is pressed in the minibuffer). By default it is bound to consult-mu-contacts--list-messages-action which searches for all the messages from that contact by calling consult-mu. You can also set this action to other functions such consult-mu-contacts--insert-email-action or consult-mu-contacts--copy-email-action for inserting or copying the email from contact.

Note that the default action for consult-mu-contacts-embark is inserting the email. This is useful for quickly adding contacts when composing messages. You cna also use embark-collect or embark-export to select multiple contacts and act on all of them (e.g. insert all in “To:” field in a compose buffer).

consult-mu-contacts-ignore-list

This is a list of rgexp that gets ignored when searching contacts. This is useful to filter certain invalid addreses (e.g. “no-reply” addresses from contacts). For example you can remove no-reply adresses by setting this variable as follows;

(setq consult-mu-contacts-ignore-list '("^.*no.*reply.*$"))
consult-mu-contacts-ignore-case-fold-search

This variable defines whether consult-mu-contacts uses case insensitive search when matching against consult-mu-contacts-ignore-list (see above). if you set this to t, it will preform case *in*sensitive match.

Features and Demos

For a detailed description of why this package is useful, and some useful screenshosts showing work flows, you can read my blog post here:

https://www.armindarvish.com/post/improve_your_mu4e_workflow_with_consult-mu/

Search

consult-mu uses consult’s asynchronous search feature. In order to search a query you can type your standard Mu4e query after # sign in the minibuffer. Here are some examples:

#tickets
#flag:unread
#(flag:unread AND maildir:/inbox)
#(maildir:/drafts OR maildir:/sent)

In addition, you can pass command line arguments that you can normally pass to mu (see mu find --help) in the command line to consult-mu by using a -- separator like this:

#tickets -- --maxnum 500 -s s

In the example above, the maximum number of results to retrieve are set to 500 (--maxnum 500) and the result are sorted by the subject (-s s). For more details on command line options, you can refer to mu’s help (i.e. run mu find --help in terminal).

Once consult-mu retrieves a list of results, you can further narrow down the list of candidates by using a second #.

#tickets -- -z #concert

In the example above, we first run a search for tickets and sort the results with reverse order (using -z option) then narrow down the list of candidates by the word, concert.

Note that narrow downs are similar to other narrow downs in the minibuffer, therefore here you cannot use mu4e search syntax but you can use regular expressions. Also, the narrow down searches in the entire header string, therefore you can use any information available in the headers (date, title, email addresses, flags,…) for narrow down. (to change the format of the header, take a look at =consult-mu-headers-template=. Here is a screenshot for doing a search and narrow:

https://github.com/armindarvish/consult-mu/blob/screenshots/screenshots/consult-mu-search-narrow.gif

Saved Searches and Quick Access History

consult-mu does have a history variable and keeps record of your previous searches. These searches can quickly be accessed using previous-history-element (bound to M-p by default). In addition, you can have a list of saved searches for quick access by modifying the variable consult-mu-saved-searches-dynamic or consult-mu-saved-searches-async for consult-mu-dynamic and consult-mu-async, respectively. These are lists of mu4e query strings that get added to future-history when you run consult-mu-dynamic or consult-mu-async. By default, consult-mu-saved-searches-async is set to inherit from consult-mu-saved-searches-dynamic, but you can modify them independently. This allows separating saved searches that are more suitable for async search from those that are better done with dynamic collection.

Similarly consult-mu-compose-attach, consult-mu-compose-detach, and consult-mu-contacts have their own history elements as wels future history elemetns (for example email in the current message buffer gets added to future-history for searching contacts).

Integration with Embark

consult-mu provides integration with embark defined in consult-mu-embark.el If you use embark, you can use these commands to run actions on the search results directly from minibuffer. For example, you can call consult-mu-embark-reply to reply to a message or consult-mu-embark-mark-for-refile to refile (a.k.a. archive) the message and so on.

For marking, note that, by default when consult-mu-embark is loaded, it creates a function for every item in the mu4e-marks and binds them to the :char for that mark in consult-mu-embark-messages-actions-map.

You can also use embark-select and embark-act-all to run the same command on multiple messages, but this only works in consult-mu-dynamic and not so well with consult-mu-async because with consult-my-async, only one message at a time is added to the headers view and therefore running commands on multiple candidates with embark is not supported.

Extras (attachments, contacts, …)

In addition to improvements for searching, consult-mu also provides extra features for composing, contacts, … These features are defined in the files under the extras folder.

Attachments

By default, attaching files to emails with mu4e is not very intuitive or interactive. If you use org-msg, it provides an interactive command for attaching files, but it is only for one file at a time and for each file you need to go through some menus. Some emacs configs, like doomemacs, do provide their own commands to allow using a dired buffer to attach multiple files to an email (see +mu4e/attach-files). Personally, I prefer using a minibuffer completion (instead of switching to a dired buffer) unless I am already in a dired buffer. The consult-mu-compose provides the utilities and customization settings to achieve interactive multi-file attachment.

To use attachment extras, you need to load the compose module by:

(require 'consult-mu-compose)
(require 'consult-mu-compose-embark) ;;optionally load embark actions for compose

It is highly recommended that you also change the preview key binding for consult-mu-compose to something other than =’any= because seeing a preview of every file when you are navigating through the minibuffer may be slow and annoying. It’s easier to get a preview of the files you are interested in with a key binding like M-o than to see a preview of every file.

(setq consult-mu-compose-preview-key "M-o")

Attaching Files

consult-mu-compose-attach provides an interactive command to attach files to an email and it tries its best to provide an intuitive interface.

Here are some features:

  • interactively selecitng draft compose buffer:

In a compose buffer (e.g. mu4e-compose-mode, message-mode, org-msg-edit-mode), it assumes that the user wants to attach files to the current message. In other buffers it asks the user to select a current compose buffer or creates a new one if noe exists.

  • interactively selecting files:

For selecting files, it can either use minibuffer completion or a dired buffer. If the customization variable consult-mu-compose-use-dired-attachment is set to always, it always uses dired buffer similar to what dom emacs does. If it is set to =’in-dired= it only uses dired when inside a dired-mode buffer. and if it is set to nil, it will always use minibuffer completion. When using dired to chose files, one can mark multiple files to attach to a message. Furthermore, if the command consult-mu-compose-attach is called from within a compose buffer (e.g. mu4e-compose-mode, message-mode, org-msg-edit-mode), runing embrak-dwim on the file will attach the file to the current message. This is specially useful if you use embark-dwim with no-quit option (embark#quitting-the-minibuffer-after-an-action). Here is an example on how to define embark-dwim-noquit:

(defun embark-dwim-noquit ()
     "Run action but don't quit the minibuffer afterwards."
     (interactive)
     (let ((embark-quit-after-action nil))
       (embark-dwim)))

Then you can just attach multiple files to the same message from any folder by using the minibuffer completion. See the screenshot in my blog post here: https://www.armindarvish.com/post/improve_your_mu4e_workflow_with_consult-mu/

Removing attachments:

Similarly, consult-mu-compose-detach provides an interactive command to remove files that are already attached to the current message. It uses minibuffer completion to select a file to remove. Similar to what mentioned above, embark-dwim (or a no-quit version of it) can be used to remove multiple files from the same message. note that the minibuffer completion list does not get dynamically updated when a file is removed (This is something I may improve in the future but for now it works just fine I think). See the screenshot in my blog post here: https://www.armindarvish.com/post/improve_your_mu4e_workflow_with_consult-mu/

Contacts

consult-mu-contacts provides an interactive way to search mu contacs. By default, when a candidate is selected, all the emails form the contact is searched by using consult-mu. This can be customized to oyher functions (e.g. compose an email to the contact) by seeting consult-mu-contacts-action. Note that mu does not have a stored list of contacts. Rather, contacts are generated dynamically from the email fields in all messages in the database, including email fields that might be invalid! To use consult-mu-contacts, you need to load the contacts module by:

(require 'consult-mu-contacts)
(require 'consult-mu-contacts-embark) ;;optionally load embark actions for contacts

See the screenshot in my blog post here: https://www.armindarvish.com/post/improve_your_mu4e_workflow_with_consult-mu/

Bug reports

To report bug, first check if it is already reported in the *issue tracker* and see if there is an existing solution or add relevant comments and discussion under the same issue. If not file a new issue following these steps:

  1. Make sure the dependencies are installed, and both mu4e and consult work as expected.
  2. Remove the package and install the latest version (along with dependencies) and see if the issue persists.
  3. In a bare bone vanilla Emacs (>=28) (e.g. emacs -Q), install the latest version of consult-mu (and its dependencies) without any configuration or other packages and see if the issue still persists.
  4. File an issue and provide important information and context in as much detail as possible in your bug report. Important information can include:
  • Your operating system, version of Emacs (or the version of emacsen you are using), version of mu/mu4e and consult (see pkg-info).
  • The installation method and the configuration you are using with your consult-mu.
  • If there is an error message, turn debug-on-error on (by M-x toggle-debug-on-error) and include the backtrace content in your report.
  • If the error only exists when you have some other packages installed, list those packages (e.g. problem happens when evil is installed)
  • It would be useful, if you can look at consult-mu buffers while the minibuffer command is active (by default they are named *consult-mu-headers* and *consult-mu-view* buffers) and report whether theya re getting populated properly or not.

Contributions

This is an open source package, and I appreciate feedback, suggestions, ideas, etc. There are lots of functionalities that can be added to this package to improve different user’s workflows, so if you have some ideas, feel free to file an issue for a feature request.

If you want to contribute to the code, please note that the main branch is currently stable (as stable as a work in progress like this can be) and the develop branch is the current work in progress. So, start from the develop branch to get the latest work-in-progress updates and create a new branch with names such as feature/name-of-the-feature or fix/issue, … Do the edits and then create a new pull request to merge back with the develop branch when you are done with your edits.

Importantly, keep in mind that I am using a literate programming approach (given that this is a small project with very limited number of files) where everything goes into consult-mu.org and then gets tangled to appropriate files (for now that includes consult-mu.el and consult-mu-embark.el). If you open a pull-request where you directly edited the .el files, I will likely not approve it because that will then get overwritten later when I tangle from the .org file. In other words, Do Not Edit The .el Files! only edit the .org file and tangle to .el files.

What about other packages? Why we need a new package such as consult-mu?

While mu4e’s built-in search is great and provides ways to edit search terms (e.g. mu4e-search-edit) or toggle search properties (e.g. mu4e-search-toggle-property), the interface is not really intuitive. We are simply too impatient in 2024 to use a static search field and edit in steps. A dynamically updated search results is somewhat expected with any modern tools. Try searching in Thunderbird, or Outlook, and you instantly see suggestions and results. This is what consult-mu provides. Hopefully, in the future a dynamics search approach comes built-in with mu4e but until then, this package intends to fill the gap.

What about alternative approaches like counsel-mu or consult-notmuch?

You can read my blog post for some thoughts on this: https://www.armindarvish.com/post/improve_your_mu4e_workflow_with_consult-mu/

Both counsel-mu and consult-notmuch inspired this package. But this package provides soemthing more than those packages. Here is the comparison:

  • counsel-mu: counsel-mu provides an async search for mu, and when the candidate is selected, the single message is loaded by using mu4e-view-message-with-message-id. consult-mu takes a similar approach in consult-mu-async but expands on that with the following features:

    a. ability to dynamically add command line options (e.g. using query -- -s s -z as input). This includes dynamically changing the number of results. This is important because with counsel-mu, one ha to change the variable mu4e-search-results-limit globally to see many results, which then affects every mu4e-search that is done.

    b. ability to load a preview without leaving minibuffer search

    c. ability to use emabrk actions on candidates from the minibuffer with consult-mu-embark

    d. ability to see whole threads when selecting a candidate rather than just single messages

    In addition, consult-mu provides the consult-mu-dynamic interactive command that uses dynamic collection using mu4e-search (and not mu commands). This allows doing dynamic search in the minibuffer and then getting a full list of results similar to the built-in mu4e-search.

  • consult-notmuch: consult-notmuch is great IF you use notmuch-emacs. consult-mu on the other hand provides similar functionality for mu/mu4e. The comparison therefore comes down to comparing mu4e and notmuch. While notmuch is light and fast, I think it lacks lots of basic functionalities of an email client. It is supposed to be not much after all! As a result, using notmuch as an everyday email client can be challenging especially if you want to use it along with other IMAP-based email clients (e.g. mobile apps). This is because the philosophy of using tags instead of folders requires a complete redesign of some workflows. While some services, like Gmail, use labels, others may not and even if they do, in IMAP-based clients labels are treated as different folders and therefore syncing back custom notmuch labels everywhere (e.g. between notmuch on your desktop machine and your mobile app client) becomes tricky. Of course, in Emacs nothing is impossible and there are ways to improve the experience by adding additional custom elisp (see Emacs: Notmuch demo (notmuch.el) - YouTube and Notmuch as an alternative to mu4e : emacs for some examples), but at the end, the results will still likely lack some important features (like multi-account contexts, …).

More importantly, a common reason to choose notmuch over mu4e is its speed, but using the underlying mu server and command line can also be very fast. In fact, at least in my own tests, consult-mu-async, which uses the command line mu commands was faster than consult-notmuch. With the latest release of mu4e (version 1.12), even consult-mu-dynamics (a.k.a. built-in mu4e-search) is now very fast. Therefore, using mu4e with consult-mu provides the best of both worlds to me. When I need speed and simplicity, I can use consult-mu-async to do a fast search (and find thousands of hits) and quickly narrow down to what I am looking for; and when I need a more complete and full-feature client I can use mu4e built-in functionalities, and with addition of dynamically built searches with consult-mu-dynamic, I have a modern intuitive interface as well.

Acknowledgments

Obviously this package would not have been possible without the fabulous mu/mu4e, and consult packages. It also took inspiration from other packages including but not limited to counsel-mu, consult-notmuch, and doomemacs.

About

Consult Mu4e asynchronously in GNU Emacs


Languages

Language:Emacs Lisp 100.0%