I’m really new to applescript and have been struggling to find the best way to extract text from an email and create an iCal event. The email’s are consistent and look similar to below. I would like an applescript to pull out the location (in this case Suite 4A / 46-56 Holt Street SURRY HILLS, NSW 2010) , StartDate (in this case Wednesday 06/08/2008 9:00am) and EndDate (which will be 1 hour after start date) and Description. Any help would be greatly appreciated. Thanks.
email contents:
Hi Joe Bloggs
We are pleased to let you know we have booked a job for you.
Job ID 26446
When: Wednesday 06/08/2008 9:00am
Name: Mr Roger Jones
Address: Suite 4A / 46-56 Holt Street SURRY HILLS, NSW 2010
Phone: 02 9310 3000
Work:
Mobile: 0415 000 470
Access Notes:
Job Description: NEC laptop. WinXP. Unable to log into windows.
Notes:
tell application "Mail"
set ms to message 1 in mailbox "Drafts" of account "your account name" -- This gets the message. Yours may be different.
set bdy to content of ms
set pars to every paragraph of bdy as list
end tell
repeat with eachpar in pars
if eachpar contains "Address:" then
set Loc to eachpar
else if eachpar contains "When:" then
set startdate to text 7 thru -1 of eachpar
end if
end repeat
If you select the corresponding eMail message in Apple Mail, this code will get you started:
on run
tell application "Mail"
set msg to item 1 of (selection as list)
set msgbody to content of msg
end tell
set joblocation to missing value
set jobdescription to missing value
set jobstart to missing value
set bodylines to paragraphs of msgbody
repeat with bodyline in bodylines
if bodyline begins with "Address:" then
set joblocation to my extractinfo(bodyline)
else if bodyline begins with "When:" then
set jobstart to my extractinfo(bodyline)
else if bodyline begins with "Job Description:" then
set jobdescription to my extractinfo(bodyline)
end if
end repeat
end run
on extractinfo(bodyline)
set offsetspace to offset of " " in bodyline
set theinfo to ((characters (offsetspace + 1) through -1 of bodyline) as Unicode text)
return theinfo
end extractinfo
I guess the only problem will be the conversion of the date string to a valid AppleScript date object.
fantastic work guys, thanks so much - especially you Martin, I was able to get it to work a couple of additions to your code. For your reference, here is the working version…
on run
tell application "Mail"
set msg to item 1 of (selection as list)
set msgbody to content of msg
end tell
set joblocation to missing value
set jobdescription to missing value
set jobstart to missing value
set bodylines to paragraphs of msgbody
repeat with bodyline in bodylines
if bodyline begins with "Address:" then
set joblocation to my extractinfo(bodyline)
else if bodyline begins with "When:" then
set jobstart to my extractinfo(bodyline)
else if bodyline begins with "Job Description:" then
set jobdescription to my extractinfo(bodyline)
end if
end repeat
set the jobstart to date (jobstart)
my CalendarLoad(joblocation, jobdescription, jobstart)
end run
on extractinfo(bodyline)
set offsetspace to offset of " " in bodyline
set theinfo to ((characters (offsetspace + 1) through -1 of bodyline) as Unicode text)
return theinfo
end extractinfo
on CalendarLoad(joblocation, jobdescription, jobstart)
tell application "iCal"
tell calendar "Work"
make new event at end with properties {description:jobdescription, summary:"text", location:joblocation, start date:jobstart, end date:jobstart + 60 * minutes}
end tell
end tell
return
end CalendarLoad
just for fun,
a version based on Martin’s script with a date conversion routine, which works completely independent from international date format settings.
I’ve added the Job ID as summary
property theCalendar : "myCalendar"
tell application "Mail"
set msg to item 1 of (get selection)
set msgbody to content of msg
end tell
set {joblocation, jobdescription, jobstart, jobID} to {"", "", "", ""}
set bodylines to paragraphs of msgbody
repeat with bodyline in bodylines
if bodyline begins with "Job ID" then
set jobID to my extractinfo(bodyline)
else if bodyline begins with "Address:" then
set joblocation to my extractinfo(bodyline)
else if bodyline begins with "When:" then
set jobstart to my extractinfo(bodyline)
else if bodyline begins with "Job Description:" then
set jobdescription to my extractinfo(bodyline)
end if
end repeat
set jobstart to convertDate(jobstart)
tell application "iCal"
tell calendar theCalendar
make new event at end of events with properties {start date:jobstart, end date:jobstart + hours, location:joblocation, description:jobdescription, summary:jobID}
end tell
end tell
on extractinfo(bodyline)
set offsetspace to offset of " " in bodyline
set theinfo to ((characters (offsetspace + 1) through -1 of bodyline) as Unicode text)
return theinfo
end extractinfo
on convertDate(dateString)
set cd to current date
set {TID, text item delimiters} to {text item delimiters, space}
set {wk, _date, _time} to text items of dateString
set text item delimiters to "/"
set {dy, mn, yr} to text items of _date
set text item delimiters to ":"
tell _time to set {t, am_pm} to {text 1 thru -3, text -2 thru -1}
set sc to 0
if (count text items of t) is 3 then
set {hr, mi, sc} to text items of t
else
set {hr, mi} to text items of t
end if
set text item delimiters to TID
tell cd to set {year, its month, day, its hours, its minutes, its seconds} to {yr, mn, dy, hr, mi, sc}
if am_pm is "pm" then
if cd's hours is not 12 then set cd to cd + 12 * hours
else
if cd's hours is 12 then set cd's hours to 0
end if
return cd
end convertDate
you guys are geniuses. Hey, just one really dumb noobie question… The code works on the selected message; what I want to do is have a rule in mail trigger the script; I have the rule set up to start the script, but I’m assuming the code needs to be modified slightly for this scenario?? Again, thanks in advance
using terms from application "Mail"
on perform mail action with messages theMessages for rule theRule
repeat with theMessage in theMessages
tell application "Mail"
set msgbody to content of theMessage
end tell
set {joblocation, jobdescription, jobstart, jobID} to {"", "", "", ""}
set bodylines to paragraphs of msgbody
repeat with bodyline in bodylines
if bodyline begins with "Job ID" then
set jobID to my extractinfo(bodyline)
else if bodyline begins with "Address:" then
set joblocation to my extractinfo(bodyline)
else if bodyline begins with "When:" then
set jobstart to my extractinfo(bodyline)
else if bodyline begins with "Job Description:" then
set jobdescription to my extractinfo(bodyline)
end if
end repeat
set jobstart to my convertDate(jobstart)
tell application "iCal"
tell calendar theCalendar
make new event at end of events with properties {start date:jobstart, end date:jobstart + hours, location:joblocation, description:jobdescription, summary:jobID}
end tell
end tell
end repeat
end perform mail action with messages
end using terms from
on extractinfo(bodyline)
set offsetspace to offset of " " in bodyline
set theinfo to ((characters (offsetspace + 1) through -1 of bodyline) as Unicode text)
return theinfo
end extractinfo
on convertDate(dateString)
set cd to current date
set {TID, text item delimiters} to {text item delimiters, space}
set {wk, _date, _time} to text items of dateString
set text item delimiters to "/"
set {dy, mn, yr} to text items of _date
set text item delimiters to ":"
tell _time to set {t, am_pm} to {text 1 thru -3, text -2 thru -1}
set sc to 0
if (count text items of t) is 3 then
set {hr, mi, sc} to text items of t
else
set {hr, mi} to text items of t
end if
set text item delimiters to TID
tell cd to set {year, its month, day, its hours, its minutes, its seconds} to {yr, mn, dy, hr, mi, sc}
if am_pm is "pm" then
if cd's hours is not 12 then set cd to cd + 12 * hours
else
if cd's hours is 12 then set cd's hours to 0
end if
return cd
end convertDate
Unfortunately that script does not seem to work, so I have reverted to the one that is working. However, I have one problem; the script does a perfect job of reading out each line for Description, Time of appointment etc… but, what I really need is more than 1 line for the description. In fact, it would probably be easier just to have all text past the word Description: but I just cant work out how to do it. Any ideas on this one?
For example, here is a description of a different job (notice how the description spans 2 lines)
Job Description: Dell Laptop. XP. Cable wired.
Getting msgs saying that she has virus. Log on page used to be her work but now it is google. running slowly.
Notes:
To consider more than one description line try this
.
set bodylines to paragraphs of msgbody
repeat with i from 1 to (count bodylines)
set bodyline to item i of bodylines
if bodyline begins with "Job ID" then
set jobID to my extractinfo(bodyline)
else if bodyline begins with "Address:" then
set joblocation to my extractinfo(bodyline)
else if bodyline begins with "When:" then
set jobstart to my extractinfo(bodyline)
else if bodyline begins with "Job Description:" then
set jobdescription to my extractinfo(bodyline)
repeat while item (i + 1) of bodylines does not start with "Notes"
set jobdescription to jobdescription & return & item (i + 1) of bodylines
set i to i + 1
end repeat
end if
end repeat
set jobstart to my convertDate(jobstart)
.
I’m wondering that Martin’s script doesn’t work. the syntax is correct
Please forgive me if I sound overly critical here. The conversion routine may be independent of the International settings on the computer running the script, but it assumes (has to assume) that the short date in the message is in day/month/year order. I may be wrong, but it seems to me from johnagr’s description that the messages come from some system designed to send e-mails to his computer, in which case it seems reasonable to assume that the short-date order will match anyway.
The routine offered is definitely not independent of OS version. The hours, minutes, and seconds settings don’t work on systems earlier than Tiger and setting the month by numeric string won’t work before Panther.
Any date-construction method that begins with the current date runs the risk of returning the wrong results with certain combinations of current date and target date. Say the script is run at the end of this month and the date in the message is a few days later, say 5th September:
set cd to date "Sunday 31 August 2008 00:00:00" -- Result of 'current date'.
set {dy, mn, yr} to {"05", "09", "2008"} -- Result of parsing the short date.
tell cd to set {year, its month, day} to {yr, mn, dy}
cd
--> date "Sunday 5 October 2008 00:00:00"
cd’s month is set to September while its day is still 31, causing it to overflow into October. The only reliable work-rounds are to set cd’s day to 1 first or to start off with a known safe date. I quite like this, which works on any system:
set cd to date "Monday 1 December 1000 00:00:00" -- Or any day in December, any year.
set {dy, mn, yr} to {"05", "09", "2008"}
tell cd to set {year, day, day} to {yr - 1, mn * 32, dy}
cd
--> date "Friday 5 September 2008 00:00:00"
The ‘tell cd’ line here changes cd’s date to December in the year before the target, then sets the day high enough to overflow into the early part of the required month in the target year, then sets the day again to the required day.
I have a similar scenerio whereby I need to extract addresses from selected emails if they meet certain criteria (such as if the text “Backup” is found in the body of the email).
My format is as such:
Address
John Doe
510 country lane
Spring, TX 78620
US
I need to copy each address with name and paste into a Word document for label creation. If anyone can add to this, I would appreciate the help. It’s been 4 years since I wrote my first intricate AS!
As you see, the intermediate value of cd is the same than yours but the final result is different.
Yvan KOENIG (VALLAURIS, France) mardi 15 avril 2014 21:05:31
I’m really puzzled because on my French system, I may set mn fro 1 thru 12, I get a wrong date.
Trying to understand I splitted the final instruction into 3 steps but it’s no more clear.
The “overflow” method I used for setting the month (ie. setting the month to December and then setting the day to 32 times the month number) doesn’t work well in recent versions of Applescript. It’s also not necessary, as it’s possible to set the month directly by number. There’s also a bug in early dates now which causes a mismatch between the time string (or the time in the date as string) and the value of the date’s time property.
"1/1/1 00:00:00"
set cd to date result --> date "Monday 1 January 0001 00:00:00"
-- But:
cd's time --> 75 on my system, not 0.
The degree of error depends on whereabouts in the world you are. It’s the property value which is correct, not the string, so you’d now also have to set the time to 0 if you set a date this way. It’s better nowadays to build a date in something like one of the following two ways:
set cd to (current date)
tell cd to set {its day, its time, its year, its month, its day} to {1, 0, "2008", "09", "05"}
cd --> date "Friday 5 September 2008 00:00:00"
-- Or:
set cd to «data isot303030312D30312D3031» as date
tell cd to set {its year, its month, its day} to {"2008", "09", "05"}
cd --> date "Friday 5 September 2008 00:00:00"
Only properties displayed in blue require the prefix its. For those displayed in purple its just wasted typing.
Why are you defining some values as strings ?
I get the same result when I define them as integer.
As I am lazyI would use :
"9/9/9"
set cd to date result
tell cd to set {year, its month, day} to {2008, 9, 5}
cd
Playing the fool, I determining the number of characters.
version 1
set cd to (current date)
tell cd to set {day, time, year, its month, day} to {1, 0, "2008", "09", "05"}
cd
According to the statistics service from Word Services there are 106 characters (including the spaces)
According to Pages 4.3 stats tool there are 104 characters (including the spaces)
If I remove the double quotes and the leading zeroes, Pages report 96 characters and the service report 98.
version 2
set cd to «data isot303030312D30312D3031» as date
tell cd to set {year, its month, day} to {"2008", "09", "05"}
cd
According to the statistics service from Word Services there are 106 characters (including the spaces)
According to Pages 4.3 stats tool there are 104 characters (including the spaces)
If I remove the double quotes and the leading zeroes, Pages report 96 characters and the service report 98.
With my preferred one they are only 76 characters (police count) or 78 characters (demonstrators count).
For sure, you’re right, I spent 1052 characters to prove that my scheme spare 28 of them (76 versus 104).
Yvan KOENIG (VALLAURIS, France) mercredi 16 avril 2014 16:23:56
All properties are green under my formatting preferences, which I’ve been using since the Apple defaults were all black.
Nowadays, I often use ‘its’ anyway (where appropriate) for clarity, or for consistency when some of the properties require it anyway.
Just following on from my 2008 script (post #10 above), which in turn was a comment on Stefan’s and Martin’s scripts (#5 and #7), which contain handlers for deriving date objects from short-date texts.
I must apologize; It was odd to assume that everybody use the default colorisation scheme. After all, I don’t use it. I force some objects to be underlined which is a neat way to see words which are in fact a single language component.
About its, I’m just too lazy to type it everywhere and use it only when it’s required. I have a post-it about that in case my memory fails.
Yvan KOENIG (VALLAURIS, France) mercredi 16 avril 2014 21:53:20