Applescript to show unread emails in the terminal
If you are on OSX and use Mail.app, but work a lot in the command line and would like a simple command to print a summary of unread emails, then this post is for you.
For this we are going to use AppleScript. We'll see at the end why applescript is not necessarily a great scripting language, but it let's us control graphical applications. This means we can do things that are hardly possible otherwise.
Just print the amount of unread emails
Let's start with a first version:
#!/usr/bin/osascript on run tell application "Mail" return the unread count of inbox end tell end run
This script just prints the total number of unread emails in all accounts. Save it in a file named "unread-emails" and make it executable with
chmod +x unread-emails. Then you can call it from anywhere if the script is in your
We've already learned a few things. We now know the shebang line for applescripts. This
Back to our script, there is a main
on run block which is the main function that is called when starting a script. I am not sure it is needed but I always put it in case I add arguments to the command. Then you have what is called a
tell block. It puts you in the context of the Mail application so that you can control it. Once in this block, you can send instructions like
check new mail or access specific objects like mailboxes and messages.
Then comes the line that actually gets the total number of unread emails. It should be self explanatory since applescripts are so verbose. It makes then easy to read, but not easy to write. And you can see the first most annoying thing: there is no easy way to print to
stdout from an applescript as far as I know. One way is to use
do shell script to use a shell command like
printf. The other way is to return something from
on run because it will be printed.
I used the
return method because otherwise each
do shell script starts a new subprocess. However you'll see it is not great either because it means if you print a lot of things, you need to set an output string and add to it until you're done and can return it.
Anyway, this little script should work, it prints the amount of unread emails in all accounts.
Separate each mail account
If you are like me, you have more than one account, and some of them are disabled. Here is a new version which prints the amount of unread emails for each account.
#!/usr/bin/osascript on run tell application "Mail" set myOutput to "" repeat with a in every account whose enabled is true set accountName to name of a set myMailbox to mailbox "INBOX" of account accountName set myOutput to myOutput & accountName & ": " set myOutput to myOutput & unread count of myMailbox set myOutput to myOutput & "\n" end repeat set myOutput to myOutput & "\nTotal: " & unread count of inbox return myOutput end tell end run
Definitely more meaty. The first thing to note is that now we are using
set ... to ... a lot. This is how you set a variable in applescript. The first variable is the string we will build up to return it as output.
We then iterate through accounts with a
repeat loop. We use a
whose statement to filter accounts and only get the ones that are enabled. For each account we print the account name and the amount of unread emails. The
& is how you concatanate strings in applescript. And the way you get a property of a record is with
name of a. You can also use
a's name which is supposed to read better, but as a developer I would rather have a dot notation to be honest.
One thing to note is that the way you get the count for one account is slightly different. The
inbox shortcut seems to only work when it is for all accounts. When counting on a single account, you need to name the inbox explicitly with
mailbox "INBOX" of account accountName.
At the very end, we print the total amount of unread emails like before and then return the string to be printed. When running this command, you should see an output like this:
Perso: 2 Work: 1 Enq: 1 Total: 4
Add a summary for each unread email
Alright, so far so good. Now let's add a little summary for each unread email with the sender and the subject line.
#!/usr/bin/osascript on run tell application "Mail" set myOutput to "" repeat with a in every account whose enabled is true set accountName to name of a set myMailbox to mailbox "INBOX" of account accountName set myOutput to myOutput & accountName & ": " set myOutput to myOutput & unread count of myMailbox set myOutput to myOutput & "\n" repeat with msg in every message of myMailbox whose read status is false set myOutput to myOutput & "- " & sender of msg & "\n" set myOutput to myOutput & " " & subject of msg & "\n" end repeat end repeat set myOutput to myOutput & "\nTotal: " & unread count of inbox return myOutput end tell end run
The output should now look like this:
Perso: 2 - Mom <email@example.com> Did you receive my funny cat images ? - Dad <firstname.lastname@example.org> You need to help me set the wifi printer Work: 1 - Boss <email@example.com> Urgent !!! Enq: 1 - <firstname.lastname@example.org> This is not a spam. I've lost 20 kg in 1h. Total: 4
The only difference in the script are these lines which iterate through unread messages:
repeat with msg in every message of myMailbox whose read status is false set myOutput to myOutput & "- " & sender of msg & "\n" set myOutput to myOutput & " " & subject of msg & "\n" end repeat
So it iterates through the messages of the current mailbox that are unread (i.e. read status is false). And then for each one we display the sender and the subject line with a bit of indentation for clarity.
There are obviously a lot of things that can be improved. We could check for new mails and wait before printing all this info. Also we could use a bit of color. That would be trivial in a shell script, but applescript is not primarily made to interract with command line. We probably would have to process the output through another command which adds colors.
Conclusion on Applescript
I don't personally know anybody who is really confortable with applescript. In my opinion, the main reason is because it is too verbose for somebody who's a developer, yet too technical for an average user. This is probably why Apple created the Automator layer on top of it.
One other reason is that error messages are not really helpful. The intention is that it reads like english, but then you miss a trivial word and get a cryptic message that is hard to interpret, even for a trained developer.
Speed can also be an issue because we essentially control graphical applications. This obviously defeats the point of a command line interface. For example printing unread messages like we just did could be more efficient if we used a command line mail client like Mutt. But writting an applescript is a good option when you want to come up with a quick and dirty solution. Or simply when there is no other way.
My advice would be to use it only for the needed part and do the rest with shell scripts. I mean a clear short task. Although if you're writing a script that is meant to be used by somebody who is not technical, then that is where it shines. You can write a script that you start with a double click, then use system dialog boxes instead of the typical
stdin/stdout flow. You can even use the system panel for choosing files. Or you can create droplets with the
on open block.