Using Mutt for my e-mail, I’d like to see full details of meeting requests that people send me in Microsoft Exchange. Unfortunately, getting e-mails out of Exchange has always proven to be a pain in the past, and meeting requests have fallen into the same bucket. I’ve essentially resorted to a single Outlook rule (it’s actually, an Exchange server-side rule) to forward all incoming e-mail to my Mutt mailbox as an attachment.

Why as an attachment? If it’s not, you lose all the message headers, can’t find out who the e-mail was CC’d to, and all the e-mail looks like it comes from me. That’s not really very useful, or how forwarding works in pretty much every other MTA on the planet (thanks Microsoft).

This means that all e-mail arriving in Mutt forwarded from Exchange comes from me (my Exchange mailbox) and goes to me (my Mutt mailbox), and contains a MIME attachment of type message/rfc822, which is the actual message I’m interested in. Makes searching for messages in the index rather difficult, but at least all the information is preserved.

So, meeting requests end up in Mutt with a message/rfc822 attachment, containing a multipart/alternative group of text/plain, text/html, and text/calendar (vCalendar). Mutt looks at the multipart/alternative and displays the one it knows about, which is the text/plain part. This is usually just a short summary of the meeting.

However, because it’s embedded inside an e-mail from and to me, they’re rather hard to find in my inbox. If I set Exchange to forward meeting requests not as an attachment, I can’t see who else the meeting request was sent to, as they are in the To and Cc headers of the original mail, which Exchange has now conveniently removed. And I still can’t tell that they’re actually a meeting request.

To the rescue comes the text/calendar attachment. This contains all the data I need in vCalendar format, but Mutt ignores it. We can fix that somewhat with the following Mutt configuration option:

alternative_order text/calendar

This tells Mutt to display the text/calendar part in preference to the text/plain part.

We can now tell Exchange to forward meeting requests first, not as an attachment, and not process any more rules. Then set up a rule to forward all other mail as an attachment.

To now highlight the meeting requests, I added:

color index black yellow "~b text/calendar"

which shows all meeting requests as black on yellow in the index. The pattern match is based on the body of the message containing the text ‘text/calendar’. You can’t match on things such as the ‘~~~~~~~’ line Exchange puts into the meeting requests (about the only other identifying feature) because all of the MIME parts are base64 encoded. Even the plain text one.

The final step is to decode the vCalendar text into something that’s a bit more readable. I found a nice perl script on the web by Martyn Smith that decodes them. Save the script as /usr/local/bin/vcal2text and then put the following in your ~/.mailcap file:

text/calendar; /usr/local/bin/vcal2text '%s'; copiousoutput

Finally, tell Mutt to automatically filter text/calendar MIME parts using this script:

auto_view text/calendar

And we’re done. Meeting requests show up in the index highlighted in yellow, and they decode and display nicely, looking like e-mails. Just something that slightly reduces the pain of having to work in a very Exchange-centric environment.

7 Thoughts on “Coping with Microsoft Exchange meeting requests in Mutt”

  • Can you please provide the source to the perl script? I did not find it online anywhere, the website is down and the only clue “vcal2text” is not found by google.

  • There is a ruby script here:

    I don’t know ruby, but its easily modified so it can also be piped into a pal style data file:

    require “rubygems” # apt-get install rubygems
    require “icalendar” # gem install icalendar
    require “date”

    class DateTime
    def date
    (self.offset == 0 ? (DateTime.parse(self.strftime(“%Y%m%d”) + self.icalendar_tzid)) : self).
    new_offset(Rational( – 60*60, 24*60*60)).strftime(“%Y%m%d”)
    # – 60*60 to compensate for icalendar gem/Outlook mismatch

    class DateTime
    def time
    (self.offset == 0 ? (DateTime.parse(self.strftime(“%H:%M”) + self.icalendar_tzid)) : self).
    new_offset(Rational( – 60*60, 24*60*60)).strftime(“%H:%M”)
    # – 60*60 to compensate for icalendar gem/Outlook mismatch

    cals = Icalendar.parse($<)
    cals.each do |cal| do |event|
    puts "#{} #{event.dtstart.time}-#{event.dtend.time} #{event.summary}, #{event.location}"

  • I’ve put the original script here: – remove the .txt extension after downloading. It’s pretty short, and GPL licence. Hope that’s useful. The only annoying thing is that Exchange tends to strip off other meeting attendees when forwarding the request, so you often don’t know who else is turning up. Not a lot that can be done about that, as it’s not in the e-mail to start with.

  • Thank you very much!
    It works for me. Except

    color index black yellow “~b text/calendar”

    With that option list in the mutt becomes unusable…

    But at all, I’m able for now to view new events which comes from Exchange!

  • Thanks… I’ve just noticed that the ~b text/calendar had stopped working here for some reason. It seems to be searching the body after processing throught vcal2text, which means “text/calendar” no longer appears in the message.

    I’ve now changed it to:

      color index yellow black "~b \"Dtstart     :\""
      color index black yellow "~N ~b \"Dtstart     :\""

    which matches the Dtstart line in the calendar – probably also fairly unique as e-mails go. The second line means that new calendar messages are highlighted with a bright yellow background, but once they have been read they drop back to just being yellow text. Makes them much less easier to miss!

  • << color index yellow black "~b \"Dtstart :\""
    << color index black yellow "~N ~b \"Dtstart :\""

    These settings works correct. Thank you!
    But list renderes slower. Is it expected?

    And I have one more question. Is it possible to customise title which outputs in the list, so we can have for some event not only title but the date and time of event (in the list)? For example:

    Google tech talk
    will become something like:
    Google tech talk (10/10/2011 16:00-17:00)

Leave a Reply

Your email address will not be published. Required fields are marked *