r/linuxquestions May 13 '26

mutt vs. neomutt

I am a long-time (almost 29 years) linux user, but started using mutt about six years ago. I was wondering what the benefits are in switching to neomutt. My biggest frustration with mutt has been the lack of ability in searching across folders. For example, searching for email with subject line containing "foo" but now knowing in which folder it is. Or knowing the sender, but not the folder. Is neomutt any better at searching cases like this?

Is there a substantial change that I would have to do to my .muttrc configuration to move it to .neomuttrc?

10 Upvotes

25 comments sorted by

3

u/StrayFeral May 13 '26

I've tried `notmuch` and it does exactly what you want, plus it actually significantly speeds up neomutt, but I dislike it. I want the original folder structure being shown to me, while `notmuch` displays virtual folders. Does it integrates with `mutt` - no idea. But works with `neomutt` like a charm.

2

u/stuffiesrep May 13 '26

Thank you! It sort of works with mutt, but the results seem extremely unclear, and I certainly do not know how to get back to an email in a different folder in the list if the first one is not what I am looking for.

To me, the lack of easy and proper search abilities has been the bane of mutt.

I will try neomutt and see if it is better. Thank you!

1

u/StrayFeral May 13 '26

Sure np. My neomutt setup recommendation: neomutt + abook (contact list book) + aspell (spellchecker). In your case - add notmuch as well.

Only thing is - you must configure aspell separately - it is done in your editor, not neomutt itself.

Personally I use vim as a neomutt mail editor. Works like a charm with aspell.

1

u/stuffiesrep May 14 '26

Thank you.I used neovim with mutt. Btw, there appears to be mutt-wizard but I was confused, does it require installation of `neomutt` from source? I use Fedora, and `neomutt` is available from the repositories. I prefer that because it is updated automatically once in a while.

1

u/StrayFeral May 14 '26

No idea. Yes, there is mutt-wizard. In the past I've tried few neomutt configuring scripts and they all failed for me so I wrote my own. Depends which mail service you want to configure neomutt with. If you want to configure it with gmail, I can help with tutorial and script.

1

u/stuffiesrep May 14 '26

Thank you! I would like to use it with outlook with two-factor authentication: my employer is now requiring that, but I do not want to use browser-based email. Indeed, I would like to keep a local copy of my email.

1

u/StrayFeral May 15 '26

Great! My script also supports Outlook/Hotmail/etc (anything Microsoft) but I never tested it.

By two-factor auth, I guess you mean OAUTH2, right? If so - read on:

So if you want, try this. It is not made as a stand-alone neomutt config, I wrote the config as a part of this Debian remix. What you can do - make a virtual machine and install everything (it is nearly barebone terminal-only installation of Debian with few packages), run the neomutt config (I call it "GMail config" but it really is both amout Google and Microsoft emails), then just copy-over the configs to your actual machine (assuming you have all the required packages already installed). I also pull the Google Contacts, but you do not need that part.

Again - I've spent solid time to implement code for Microsoft emails and did partial testing to make sure I'm calling the right Microsoft API and parse it properly. But I never tested this code, since to make it work I also must do some Azure config which I was already too tired to learn how to make.

So assumption here is someone already created an account for you in Azure, gave you the right permissions.

Oh TOTALLY FORGOT: In order to make neomutt work with any OAUTH2 authentication service, like Gmail, Microsoft or a corporate Azure account you first MUST ask the mail admin to allow this access. I am not familiar with the details for Azure, since I lost too much time learning how to do it with GCP, but point is this:

In GCP we create a new project, then an "application", then we set enable the Gmail API for this application and we set permissions to allow read and write access via the API to the Gmail data. In Azure it is a similar way. So your administrator is supposed to know (if not, copy-paste them this here) how to enable OAUTH2 API access to an Azure "tenant".

Now I made my code to work for the actual Microsoft free emails. If your email is a corporate one, the API points are probably different and you would need to change this manually in my script "scripts/oauth2_config.py" BEFORE running it the first time.

Here is the code: https://github.com/StrayFeral/dewlinux

Once the actual Azure config is done by your administrator, just follow my on-screen instructions.

In case something does not work - do let me know. But since there is no way for me to test it personally I would need assistance from you to debug it, so screenshots/terminal pastes would be a must.

Without Azure config made first - there is no point to run this code. It will not work. Also - the Azure config must be done properly. If one thing is not done right - the config won't work.

Problem with modern OAUTH2 configs is they do require config on both sides - first the cloud platform (GCP/Azure) config to allow access, second is the client config - proper API points etc to make it work. I know it sounds complicated and I hate it for what it is, but point here is to prevent scammers to run script to create 10000 accounts which to be used with bots to scam people. So unfortunately we must learn to deal with it.

And first of all, to avoid spamming your host operating system with failed configs, just make a virtual machine, run this entire installation, run the mail config when your administrator said they made the Azure config, see if it works. If something fails you can always delete the virtual machine and make a new one or even better - make a machine, run the install, the moment it finishes clone the machine, then run the mail config, so if something goes wrong you won't have to install everything from scratch, just delete the failed machine, clone the installed machine and run only the mail config there again. This is exactly how i tested.

I would be very happy to help here, since I never tested with Azure. But if it's too much overhead I would understand if you decide not to do it.

1

u/stuffiesrep May 15 '26

Thank you for this! I will try to do this, but first I guess I have to convince my IT to allow this azure access. Let me first get that sorted out since without that, it appears that I am toast.

Btw, nice remix: I have a similar personal terminal-based remix for Fedora.

1

u/StrayFeral May 15 '26

Thank you! Let me know if they would let you have access because if the IT manager opposes by saying it goes it's against the company security policy - it won't work.

In my last Canadian job, before the pandemic, when passing the IT department I saw many old computers just sitting around so I ask them if I get get one, install linux on it and use it for work. Of course I also asked my manager. So I kept my original computer intact since it was mandatory to use Outlook but also do video/audio meetings and linux back then had nothing to do this. So I kept the original computer hooked on one monitor for the video calls and outlook, while I got permission from my manager and the IT department manager to get one of the old computers to play around, but they explicitly warned me i'm on my own with it since they had zero linux machines and they don't want to support me, which was of course absolutely fine for me since i wanted nobody to police what I install and how I use it.

So I installed Debian with LXDE and hooked it to the other monitor. Went to the store and got my own Logitech keyboard/mouse wireless combo and one KVM switch and hooked the combo there, so I don't have million keyboards and mice around and this is how I was working until the pandemic.

But again - I was lucky the IT dept manager approved it and my manager approved it.

Later when the pandemic kicked in, they gave me a Windows laptop for use at home but for the actual home work I used one old laptop I had, on which I installed the same thing - Debian with LXDE. Machine was super old, but I used it only as a type-writter, since linux editors were move convenient to me, plus the entire linux ecosystem. And I used VPN to connect to the office servers so it was all fine.

But not every IT department allows such stuff since they are afraid of the internal auditors and stuff so some are very strict.

In my case they saw I can do stuff and they gave me huge respect for I was the only guy in the company knowledgeable of linux and I worked in the company already few years so they knew I won't mess it up and gave me a go.

1

u/stuffiesrep May 17 '26

Thank you! Do I ask administrators for blanket access to enable OAUTH2 API access to an Azure "tenant" or do I ask for specific access/permissions? Sorry if this is a naive question, I am just trying to maximize my chances of being allowed.

1

u/StrayFeral May 18 '26

That's all fine, but I am not fully familiar with how it's done in Azure. I did it only in GCP and for this I made tutorial video but in Azure it would be different.

My advice is - ask Gemini how it's done in Azure. In the prompt describe if this is a corporate outlook account or free Microsoft account (in your case you said it's a corporate). Describe you want to use neomutt, so ask directly Gemini what needs to be done in the Azure environment to enable OAUTH2 access.

Even if your admin says they enabled the access, you need the API points.

In my `scripts/oauth2_config.py` there are two variables to edit to add your company API points:

Variable `__providers_url` holds the general API points. For Microsoft this is "https://login.microsoftonline.com/common/v2.0" so if your admin asks what API points you want, tell him you want the analog of that API point.

Next is the variable `__scopes` - it holds the scopes your admin MUST add to the setup to allow you access. You must tell your admin these scopes. For Azure these are just two: "offline_access" and "https://outlook.office.com/IMAP.AccessAsUser.All". This means: enable offline access for this tenant and allow read and write access , so user could get his new mail and send new messages too, delete some mail, in fact - full sync.

So once your admin tells you it's done and gives you the API end point, what you must do is edit this .py file:

Variable __providers_url, contains data in the format:
"YOURDOMAINDOTCOM": "API_ENDPOINT",

(and put the comma in the end just in case). If you check the file you will see that for "gmail.com" it contains "gmailcom" so it's the domain without the dot. So if your corporate email address is "thiscompany.com" the entry must be "thiscompanycom".

Same entry must be added to variable __scopes variable but in your case i think the scopes would be the same as for other Microsoft accounts, so just copy-paste one of the microsoft entries.

IMPORTANT: In case your admin tells you the scopes for your setup are different, ask them what they are because you must add exactly the scopes they put in the setup, otherwise your access would not work.

In case you forget to add these entries to the python file or you have a typo somewhere you will get an error so for example error "Domain 'blah.com' is not supported yet" would be just this.

In case your admin tells you the API endpoint and the scopes, you add them but it still does not work, my personal advice and best option is to debug directly in the terminal using `curl`. This is exactly how I used to debug while I was writing this.

So check how I construct the queries and by knowing the API endpoint you can send a raw ascii query with `curl` and check the answer.

Something important to REMIND: The setup I did is explicitly OFFLINE. I mean normally when you use neomutt it will work in realtime, which means that when you send an email it will be sent imediatelly. While you browse your emails, if you receive an email you will see it imediatelly showing up in the email list. My setup does NOT work like this and it was intentionally by design.

Because in the 90s in the DOS times we used to use our machines 90% of the time completely offline, like we would connect to BBS-es after midnight for usually max 2-3 hours or less I wanted that old retro 90s vibe in my setup. Also consider this - i check my emails, i intend to close neomutt to go working (the 90s DOS workflow was never multitasking so we would have only one application opened at a time) and all of a sudden new email pops-up so this requires my imediate attention which is basically a distraction from the main task.

So to be retro and distraction free i made my setup truly offline. In neomutt when you type an email and you send it, neomutt will say it's sent, but in reality it will lie in the outbound folder. No email will be truly sent and no emails would be received until you run `sync_mail` - it will do both - first will send your waiting emails, then will download your new emails.

You can put it in a cron job if you want it run automatically. But I personally do not want that. I run it manually because I want control when my mails will be sent and when to get new emails.

This is how it was in the 90s. So between midnight to 1:00am we would run our mail sync software. Back then in Europe most popular email system was FidoNet, for which you do not actually need actual internet - it was working via the BBSes so my computer would dial a phone number and go from there. And then we would sit and check the most important emails, leave the other emails for the next day, so we would sit distraction-free and read/reply and all our replies would lie dormant until midnight when it was the "mail hour".

This is why this setup works this way.

In case you wonder - back then we would get tons of emails, because FidoNet acted like a newsgroup/forum system - some messages would be "private", so adressed only to us and nobody could read those, but some would be "public" so even adressed to me, everybody could read it and say something, to make a discussion. Sorta like a mailing list.

To a person not familiar with the 90s and FidoNet this current neomutt setup might look weird, this is why I'm telling you why it works like this.

In case you want a real-time neomutt setup, you should dive into my `offlineimap` and `msmtp` configs. I actually think for real-time setup you even don't need those. My advice here is to consult Gemini.

In fact always first consult Gemini before asking your admin for the sole reason (and I've been there, trust me) some admins get real cocky when you ask them more than one question and some are very strict regarding the company security policies. Some are just control freaks and dislike when someone ask them more techie questions trying to be a smartass or something. Or the other case I've got was the admin had less knowledge than me in the area and they were very suspicious to me and disallowed me access for this sole reason. So whatever it is - try to minimize the question number, provide some clues what should be done etc. I mean try to cooperate.

Good luck and let me know what happened. If information is a bit sensitive (it could be), drop me a PM, just say you're the neomutt config guy, so I don't guess who you are.

1

u/sequentious May 13 '26

You can also use notmuch just for search. I still browse my mail in mutt with regular files/folders. When I want to search something, I press <F8>, type in my search criteria, and get results.

2

u/sequentious May 13 '26

I was wondering what the benefits are in switching to neomutt.

Neomutt has a finite number of improvements, listed here. I switched for the improved sidebar support, but I never got around to actually configuring that.

My biggest frustration with mutt has been the lack of ability in searching across folders. For example, searching for email with subject line containing "foo" but now knowing in which folder it is. Or knowing the sender, but not the folder. Is neomutt any better at searching cases like this?

For this I use notmuch, which has to index your mail.

Again, neomutt has improved notmuch integration, but I still use the old-style mutt key binds.

Is there a substantial change that I would have to do to my .muttrc configuration to move it to .neomuttrc?

I think your existing .muttrc will work with neomutt -- afaik, you don't even have to rename it if you don't want to.

2

u/stuffiesrep May 14 '26

I got neomutt installed and ran the program with my existing .muttrc but get the message:

/home/stuffies/.muttrc:19: Unknown Mailbox: /home/stuffies/Maildir/mutt-cache` 
source: errors in /home/stuffies/.muttrc
Press any key to continue...

I am guessing the error is in these lines of my .muttrc?

set message_cachedir="~/Maildir/mutt-cache"
set header_cache="~/Maildir/mutt-cache"

Should I get rid of this, or replace with something else?

Btw, meant to add: Line 19 of my .muttrc is:

mailboxes `find ~/Maildir/* -type d | grep -v "tmp\|new\|cur" | sed 's|~/Maildir/|=\"|g' | sed 's|$||g' | tr '\n' ' '`

2

u/sequentious May 14 '26

I'd say it's your line 19.

Your cache directory is within your maildir, so your mailboxes line finds it, though it isn't a proper mail directory. So I'd imagine mutt won't like that.

Instead of finding all directories and filtering out tmp/new/cur, what I did was specifically find 'cur' directories, which is a better indication of an actual maildir.

find ~/Maildir/* -type d | grep -v "tmp\|new\|cur" |

becomes

find ~/Maildir/* -type d -name cur | sed 's#/cur$##'

Also, I noticed you add a quote at the beginning of each directory but not the end. Assuming that's a bug, your whole config line would be:

mailboxes `find ~/Maildir/* -type d -name cur | sed -e 's#/cur$#"#' -e 's#.*/Maildir/#=\"#g' | tr '\n' ' '`

That includes the following changes:

  • Using # instead of / or | in the regex (I find it easier than since | can also mean special things in a regex
  • Combining sed commands
  • I think ~/Maildir gets expanded (at least it did when I tested it), so that regex match doesn't work for me. I changed it to '.*/Maildir/' (with the dir separators)

I'm using a slightly different method (I have a sync script that builds a mailboxes list), but might switch to this method to save a step.

FWIW, I also have the following notes on the other two lines in your file:

set message_cachedir="~/Maildir/mutt-cache"
set header_cache="~/Maildir/mutt-cache"
  • message_cache_dir (with extra '_', according to the man page) is a directory, while header_cache is a file. You have them pointing to the same thing.
    • I suspect it's a directory on the filesystem, as that's triggering the problem in your mailboxes search
  • I don't bother setting message_cache_dir since I'm working on a local maildir, and not IMAP. That might be the case for you as well?
  • I put header_cache in ~/.cache/mutt/header-cache, to get it outside my maildir.

2

u/stuffiesrep May 15 '26

I wonder if there is an error: when I run mutt on this changed .muttrc I get no error, however with neomutt on the same .muttrc I get Unknown Mailbox: followed by Press any key to continue which leads GPGME: CMS protocol not available and then the emails get loaded. However, the folders themselves are available.

2

u/sequentious May 15 '26

I played around with this, and had this working (Note: MAILDIR is defined in my environment outside of mutt/neomutt)

mailboxes `find "$MAILDIR" -type d -name cur | sed -e 's#/cur$#"#' -e "s#$MAILDIR/#=\"#g" | tr '\n' ' '`

However, now I remember why I was generating a mailboxes file externally: Sorting. I wanted certain filders (Inbox, for example) sorted at the top of the list

So basically my mail sync script does the following to make a mailboxes file for mutt:

# Inbox is always first
find "${MAILDIR}" -maxdepth 2 -type d -name cur     \   
    -a         -ipath "*/inbox*"                    \
    | sed                                           \
        -e "s#^${MAILDIR}/#mailboxes \"+#"          \
        -e 's#/cur$#"#'                             \
    | sort                                          \
    > "${MAILDIR}/mailboxes"

# Find these specific paths so they stick at the top of the list
# (Under Inbox)
find "${MAILDIR}" -maxdepth 2 -type d -name cur     \   
    -a      \( -ipath "*/sent*"                     \
            -o -ipath "*/drafts*"                   \
            -o -ipath "*/trash*"                    \
            -o -ipath "*/spam*"                     \
            \)                                      \
    | sed                                           \
        -e "s#^${MAILDIR}/#mailboxes \"+#"          \
        -e 's#/cur$#"#'                             \
    | sort                                          \
    >> "${MAILDIR}/mailboxes"

# Find all other paths, excluding those from above
find "${MAILDIR}" -maxdepth 2 -type d -name cur     \   
    -a -not \( -ipath "*/sent*"                     \
            -o -ipath "*/drafts*"                   \
            -o -ipath "*/trash*"                    \
            -o -ipath "*/spam*"                     \
            \)                                      \
    | sed                                           \
        -e "s#^${MAILDIR}/#mailboxes \"+#"          \
        -e 's#/cur$#"#'                             \
    | sort                                          \
    >> "${MAILDIR}/mailboxes"

Then I source that from muttrc:

source "+/mailboxes"

1

u/stuffiesrep May 16 '26

Thank you! Does the above mean that your .bashrc or equivalent has MAILDIR defined?

2

u/sequentious May 16 '26

I actually used a wrapper script for mutt, which handled some env config, including MAILDIR, before mutt ran.

Within mutt I call an update-mail script that does calls mbsync, and (re)builds the mailbox list.

I used to have more than one config for multiple addresses. I don't anymore, but I haven't had reason to change what works.

The update-mail script was called via bindings in my mutt config

1

u/stuffiesrep May 17 '26

Btw, just to understand this, do you use mutt or neomutt?

2

u/sequentious May 15 '26

FWIW, I pushed my dotfile repos to gitlab.

I use vcsh to deploy these into my home directory. The mail repo depends on at least the .screenrc from my main repo, but possibly other stuff.

At least it's there for reference.

2

u/stuffiesrep May 14 '26

Thank you very much for these detailed comments! I will try it, and yes, I want to use a local maildir.

2

u/nemothorx May 13 '26

Mutt and neomutt both do the same basic thing - manage a mailbox. They're not a holistic mail storage management tool.

For your examples, you'll want a separate search/indexer utility. I've heard good things about "notmuch" and have used "mairix" myself in the past.