How can I determine if there is unread mail on my OSX box?

Mail is fetched from a variety of places with fetchmail, and delivered to my local user in /var/mail/user. I am searching for a way to find out if there is unread mail, or if I have read the mail (using alpine). I prefer a solution that uses unix tools, but am open to AppleScript or any other solution for the unread count part, but it must work with unix mail readers (/var/mail/user).

I'd like to have a command line tool that says if there is unread mail in the inbox, so that I can run it with a cron job, and use the keyboard_leds tool to set subtle notifiers. I prefer this to MacBiff, growlnotify, etc.

I thought I figured out one possible solution:

mail -H | grep -c '^.[NU]'

seems to sometimes return the number of unread messages. But if I read a message in alpine, it doesn't update until I quit alpine.

Another approach might be to use my mail client (alpine) directly. I have a clean .pinerc which has no colors, etc trying to make the display as simple as possible, and then run this command:

alpine -o -x .pinerc.clean -I i,q >& foo

Which runs alpine, goes to the Inbox, and then quits (leaving the inbox in read-only mode so as to not disrupt my main alpine process which is viewing the inbox). The screen dump of the inbox is stored in the file "foo".

However, foo the last screen (quitting message, not inbox) and is a binary file in this case, and I cannot figure out how to parse it for the "N" in the column that designates unread mail, even if it were there...

  • 1
    Is this a question or a blog? And are you going to award the bounty to yourself, yourself or yourself? Please group all your trials and conclusions into your post, delete all your answers and define clearly your question. At the moment it's quiet hard to understand what is exactly the point here. – harrymc Sep 8 '10 at 20:56
  • This is a question. The FAQ states, "...Document your own continued efforts to answer your question.", which is what I was doing. – user31752 Sep 8 '10 at 22:37
  • I know it says that and it's not a bad thing, it merely becomes hard to understand your progress when it's divided over 3 answers and the question itself! =) – BloodPhilia Sep 8 '10 at 23:02
  • It's much clearer when you restrict yourself to your post and let others supply the answers, even if you have found the answer yourself. – harrymc Sep 9 '10 at 10:36

You're 90% of the way there with the mail -H | grep -c '^.[NU]' command. I understand that you need this to reflect any changesd made in an open instance of Alpine however. Unfortunately this is not easy to do, but I'll lay it out for you anyway.

What you want is not directly possible because the changes to Message Status made by Alpine are done so in memory and only written out to disk periodically (at "checkpoints"). The mail command (and all variants) can only read mail information from disk, and cannot know of changes made in Alpine between checkpoints. So all you can really do is increase the frequency of checkpoints.

The code to determine when to checkpoint is very complicated but from what I can gather the default settings:

  • Won't save any more often than 180 seconds (min_interval)

  • When Alpine has been idle for more than 30 seconds it will checkpoint if 12 changes (checkpoint frequency) to the file have been made or at least one change has been made and a checkpoint hasn't been done for five minutes (checkpoint_interval).

  • When Alpine has executed some command it will checkpoint if there are 36 outstanding changes to the mail file or at least one change and no checkpoint for ten minutes.

  • When composing a message Alpine will only checkpoint if at least 48 changes have been made or at least one change has been made in the last twenty minutes with no checkpoint.

What you really want is for Alpine to write back to disk more frequently. Unfortunately the checkpoint_interval and checkpoint_frequency variables can only be changed at compile time. To do this you need to recompile Alpine, but with some configure options, namely:

--with-checkpoint-interval (default 420)
--with-checkpoint-frequency (default 12, you might want to change to 1) 

Of course, if you're going to go to the trouble of recompiling alpine you may just want to change the checkpoint code to write after each change, but be warned that whatever you do, it's likely to result in decreased performance if you increase checkpointing frequency.

One more thing to note - you can see when checkpoints occur currently by turning on the option [X] Enable Mail Check Cue. Two asterisks ** will appear when it is saving to disk.

  • Thanks for the answer. I've recompiled with --with-checkpoint-frequency=1 and it does not seem to save after every change... I'm not too worried about performance as my inbox is local (not IMAP) and has only a few messages in it at any given point in time. – user31752 Sep 15 '10 at 19:37
  • OK upon further reading of the code this cannot be configured only with options to ./configure. There are hard-coded #DEFINE statements in the code to limit frequency... – user31752 Sep 15 '10 at 19:51
  • Good to know, especially since it seems to contradict the linked newsgroup post. Good luck getting to do do what you want. This is why open source is cool (though oft painful)! – imoatama Sep 15 '10 at 23:44

Try the following script:


if [[ "$?" == "0" ]]
    then echo "You've got mail!"
    else echo "No new mail"

Replace the echo commands to suit your purpose.

  • checkmail doesn't seem to exist on OS X nor in fink. Can you provide a link to the source? – user31752 Sep 8 '10 at 22:45
  • @mankoff check out mj.ucw.cz/linux.html – BloodPhilia Sep 8 '10 at 23:01
  • Doesn't seem to compile under OS X. Also, based on the issue with mail/mailx NOT seeing mail as "read" until I quit alpine, I'm not sure that checkmail will have more success... – user31752 Sep 8 '10 at 23:10

See this article : A script to only show unread/flagged messages in Mail.app Apps:

It's a shame Mail can't display unread/flagged only messages .. or can it? Correct me if I'm wrong. Anyway, here are two scripts to filter your mailbox. Save these scripts inside Users -> your_username -> Library -> Scripts -> Mail Scripts -> anySubFolder. They'll appear under the script icon on Mail menubar. In case you don't know, you can also add shortcut keys to the scripts; I'm too lazy to tell you how, but you can open up Mail Help and find the instruction under Browse Mail Help -> Customizing Mail -> Using the Scripts Menu.

The article contains two scripts : Show unread only and Show flagged only, which not being a Mac person I can't evaluate. However, if they work, they can be easily adapted to your needs.

Here is Show unread only :

  tell application "Mail"
    set theViewer to front message viewer
    set theMsg to messages of theViewer
    set msgList to {}
    repeat with thisMsg in theMsg
      if read status of thisMsg is false then
        set the end of msgList to thisMsg
      end if
    end repeat
    if msgList is {} then
      display dialog "There's no unread message in this mailbox."
      tell theViewer to set properties to {visible messages:msgList}
    end if
  end tell
  on error the errMsg number the errNmb
  if the errNmb is not -128 then
    set the errTxt to "Error: " & the errNmb & ". " & the errMsg
    display dialog the errTxt buttons {"Cancel"} default button 1
    error number -128
  end if
end try
  • I don't use Mail.app and this solution requires use of Mail.app. It won't work with /var/mail/user... – user31752 Sep 9 '10 at 14:02
  • Sorry. I'll leave this answer here for the benefit of users of Mail.app. – harrymc Sep 9 '10 at 14:34

See if this article helps : Command-line mail on OS X: re-alpine and Geektool

While looking for remote monitoring tools at the office this week, I ran across GeekTool. GeekTool is like SilverService for notifications. All it does is display something on the desktop. At the office I’ve quickly started using it to monitor log files and remote graphs. But the shell output option is perfect for displaying incoming mails.

/usr/bin/mail -H

This is just the command-line mail program with the option to display the index of waiting mails and immediately quit. If there are messages waiting, it will display the message date and subject, and if not it will display nothing.2

So this will leave the desktop alone, unless there is mail waiting to be read from one of my cron jobs.

GeekTool is pretty cool, and you can download a bunch of pre-made “geeklets” for it (I haven’t used any of them). You can place them on the desktop and arrange them as you see fit.

  • No as you can see from the question, re-written at your advice, I've already tried this and explained the limitations. – user31752 Sep 9 '10 at 19:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy