Thursday, August 07, 2008

AppleScript to generate iCal events from email

I just figured out a way to get my work calendar copied onto my iPhone! Yay!!

A bit of background first:

My company doesn't have Exchange, or any other real "groupware". For email, there's just a simple POP server (uuurgh!) and for calendar, they have a custom-built intranet application (huh?!).

The intranet calendar system has a function to send an automatic email alert whenever somebody books an appointment with me in my calendar. The email goes to my work email account, but I have configured an Outlook rule to automatically forward it to my home email address.

When it arrives at my Mac at home (which is always on), I have a Rule in Mail.app which runs the below AppleScript. The script parses the contents of the email, and creates a new event in iCal.

iCal syncs with MobileMe, which in turn syncs with my iPhone. Hooray!!

I haven't used this in anger yet, so I'll be trying it out for the first time tomorrow.

Known limitations:

  • It's highly customised to the format of the emails I get from the intranet calendar system.
  • It doesn't automatically handle recurring events. The first event will be registered, but I have to set the recurring settings myself.
  • It doesn't handle updates or cancellations of events. If an event is moved, it will simply register it again at the new date/time. The old one will still be there.
I'm yet to discover just how long it takes for a new event to finally show up on my iPhone, but based on experience with MobileMe "push", I'm expecting at least a 15~20 minute delay.

How to install:
  1. Launch the application Script Editor and copy the code below.
  2. Save the script somewhere. I saved it in my Documents folder as "MailToCalendar".
  3. Open Mail and select Mail > Preferences... from the menu bar.
  4. Under Rules, click Add Rule.
  5. Give the rule a name (mine is "MailToCalendar").
  6. Create the conditions to recognise the alert emails (mine is Subject Contains "スケジュール予約状況案内").
  7. Add the actions Delete Message, Mark as Read, and Run AppleScript (pointing to the location of the AppleScript you saved).
  8. Click OK. That's it.
Many thanks to AK who gave me a sample AppleScript to get started with! :-)
(*
Make an iCal event from an email
AK  IT Carlow Ireland May 2005
and Will Hains Tokyo August 2008
*)

 

using terms from application "Mail" on perform mail action with messages MessageList for rule theRule -- say "Starting MailToCalendar" set OldDelim to AppleScript's text item delimiters

tell application "Mail" set ThisOne to item 1 of MessageList set TheDetails to content of ThisOne end tell --Mail

set AppleScript's text item delimiters to {"\n"} set TheDetails to text items of TheDetails set TheTopic to "" set TheStart to current date set TheEnd to current date set ThePlace to "" set TheDescription to ""

repeat with ThisDetail in TheDetails set AppleScript's text item delimiters to {"\n"} try -- find the date if "日付:" is in text item 1 of ThisDetail then set AppleScript's text item delimiters to {":"} set TheDateTimeRange to text item 2 of ThisDetail

set AppleScript's text item delimiters to {"-"} set TheStartDateTime to text item 1 of TheDateTimeRange set TheEndDateTime to text item 2 of TheDateTimeRange

set AppleScript's text item delimiters to {" "} set TheStartDate to text item 1 of TheStartDateTime set TheStartTime to text item 2 of TheStartDateTime set TheEndDate to text item 1 of TheEndDateTime set TheEndTime to text item 2 of TheEndDateTime

set AppleScript's text item delimiters to {"/"} set year of TheStart to text item 1 of TheStartDate set month of TheStart to text item 2 of TheStartDate set day of TheStart to text item 3 of TheStartDate set year of TheEnd to text item 1 of TheEndDate set month of TheEnd to text item 2 of TheEndDate set day of TheEnd to text item 3 of TheEndDate

set AppleScript's text item delimiters to {":"} set time of TheStart to (text item 1 of TheStartTime) * hours + (text item 2 of TheStartTime) * minutes set time of TheEnd to (text item 1 of TheEndTime) * hours + (text item 2 of TheEndTime) * minutes

-- say "the start is " & TheStart -- say "the end is " & TheEnd end if --Date

-- find the place if "利用設備:" is in text item 1 of ThisDetail then set AppleScript's text item delimiters to {":"} set TheMeetingRoom to text item 2 of ThisDetail set AppleScript's text item delimiters to {"会議室"} set ThePlace to text item 1 of TheMeetingRoom -- say "place is " & ThePlace end if --Place

-- find the topic if "予定:" is in text item 1 of ThisDetail then set AppleScript's text item delimiters to {":"} set TheTopic to text item 2 of ThisDetail -- say "the topic is " & TheTopic end if --Title

-- find the description if "内容:" is in text item 1 of ThisDetail then set AppleScript's text item delimiters to {":"} set TheDescription to text item 2 of ThisDetail -- say "the description is " & TheDescription end if --Description

on error errStr number errorNumber say "MailToCalendar error! " & errStr end try end repeat --iterate through fields

--set up the event in iCal tell application "iCal" -- say "Will now attempt to register in iCal" tell calendar 2 --CHANGE THIS to sequence number of target calendar set newItem to make new event at end of events with properties {start date:TheStart, end date:TheEnd} set summary of newItem to TheTopic set location of newItem to ThePlace set description of newItem to TheDescription -- say "registered in iCal" end tell --calendar end tell -- iCal

set AppleScript's text item delimiters to OldDelim -- say "finished MailToCalendar" end perform mail action with messages end using terms from

 

8 comments:

  1. This looks good, but I would like to know how to compose an e-mail to trigger this script.

    ReplyDelete
  2. The script itself is triggered by the "Rule" in Mail.app (see step #6 above). But the script is (necessarily) very specific to the format of the emails I get from my company's calendar system (which is all in Japanese):

    Here is an example email to give you an idea:

    Subject: スケジュール予約状況案内
    Body:


    スケジュールの承認依頼が下記の内容で変更されました。


    日付:2008/08/07 15:00-2008/08/07 16:00
    変更日:2008年08月05日
    変更者:鈴木 敬
    予定:テスト計画
    場所:--
    利用設備:E2S1会議室 / E2S1 room
    内容:テスト計画に関する打ち合わせ

    ReplyDelete
  3. hey, i have sort of a similar thing here at my work. i am trying to accomplish the exact same task.

    quick question, how did you test this short of sending your self bunches of emails?? is there an easy way to test it with an input email file or something?

    (im really green to applescript)

    ReplyDelete
  4. Yes there is an easier way: All you need is one email for each scenario you'd like to test, and in Mail.app you right-click (or cmd-click) the email and choose "Apply Rules".

    ReplyDelete
  5. awsome. ill give that a try!

    ReplyDelete
  6. that worked, one more thing thought... in your script you have "theRule" in the second line when you pull messages from mail... is that supposed to be set to some value?

    ReplyDelete
  7. I think it gets set to an object representing the rule that has triggered the script, but I don't use it for anything. It's just boilerplate that I copied from the original script by AK. ;-)

    ReplyDelete
  8. Thanx so much for posting this. I was looking to try something like this. The script depends very much on what the text email looks like. In my case, I started with:



    Subject: Meeting with A Person
    Item Type: Appointment
    Start Date: Wednesday, 10 Dec 2008, 02:13:00pm (CST)
    Duration: 1 Hour, 42 mins
    Place: Conf Rm 999

    I had to parse out each line to get the various items. In my case, since the time was in the format of start time and duration, I had to recreate an iCal compatible Start and End time by parsing out the hour min sec AM/PM indicator and then add duration in mins to that. I could not find much about iCal's starttime format so used number of seconds. ie 1.15AM is (1[hr]*60*60 + 15[min]*60), allowing for 12 more hours if 1pm or later (not 12pm!)



    Seems to work well on my test messages. As you say, biggest issue is recurring items do not work well, as with deleted items on the original calendar.

    ReplyDelete