(* "MailAnnounce" for Mail by Damon Parker damonp@damonparker.org $Id: MailAnnounce.scpt.txt 5 2007-04-26 15:36:26Z damonp $ based on a macosxhints.com post http://www.macosxhints.com/article.php?story=20030304111345916 I use a rule that runs MailAnnounce only on mails to/from certain email addresses or address groups (like clients). I didn't want this to announce all mails only those important ones when I am away from the desk but within earshot. v1.3 jun 10 2006 added option to skip if not idle v1.2 apr 24 2006 clean up subject speak to remove read message announcement added search and replace for subject v1.1 apr 12 2006 add subject speak v1.0 apr 1 2006 -- initial release added routine to kill script after waiting too long cleaned up sender speak options *) property announceJunk : false -- should junk mail be announced too ? property senderCntThreshold : 2 -- more than this, and the count is announced property senderCntMax : 4 -- more than this, and only the count is announced property voiceVolume : "0.3" property theVoice : "Victoria" -- name of voice to uses, see speech system preferences pane for more or leave blank for default property senderList : {} property subjectList : {} property firstRun : true -- don't do anything at first run of idle property countRun : 0 -- so we can limit the number of total runs property maxRun : 100 -- exit after this property skipNotIdle : false -- do not notify if screensaver is not running if skipNotIdle then --set saver to do shell script "ps auxw | grep -i ScreenSaver.framework" set saver to do shell script "ps -xc -o command | egrep -c \"^ScreenSaver.framework$\"" if saver does not contain "Resources" then --continue quit --tell me to quit --return ? quit return 0 --exit repeat end if end if using terms from application "Mail" on perform mail action with messages theMessages repeat with thisMessage in theMessages set thisSender to extract name from sender of thisMessage set thisSubject to subject of thisMessage set thisRead to read status of thisMessage set junk to junk mail status of thisMessage set thisDate to date received of thisMessage -- display dialog thisDate -- if thisRead is false then -- from http://www.teutonicspectator.com/2007/03/18/mail-and-itunes-for-geektool/ if thisRead = 0 then tell application "MailAnnounce" newMail(thisSender, junk, thisSubject, thisRead) --newMail1(thisMessage) end tell end if end repeat end perform mail action with messages end using terms from on newMail1(messages) if junk then if not announceJunk then return end if set thisSender to " junk " else if thisRead is true then return end if set found to false repeat with x in my senderList if sender of x is equal to thisSender then set cnt of x to (cnt of x) + 1 set found to true exit repeat end if end repeat if not found then copy {sender:thisSender, cnt:1} to end of my senderList end if set found to false repeat with x in my subjectList if subject of x is equal to thisSubject then set cnt of x to (cnt of x) + 1 set found to true exit repeat end if end repeat if not found then copy {sender:thisSender, subject:thisSubject, status:thisRead} to end of my subjectList end if end newMail1 on newMail(thisSender, junk, thisSubject, thisRead) if junk then if not announceJunk then return end if set thisSender to " junk " else if thisRead is true then return end if set found to false repeat with x in my senderList if sender of x is equal to thisSender then set cnt of x to (cnt of x) + 1 set found to true exit repeat end if end repeat if not found then copy {sender:thisSender, cnt:1} to end of my senderList end if set found to false repeat with x in my subjectList if subject of x is equal to thisSubject then set cnt of x to (cnt of x) + 1 set found to true exit repeat end if end repeat if not found then copy {sender:thisSender, subject:thisSubject, status:thisRead} to end of my subjectList end if end newMail on idle if firstRun then set firstRun to false return 2 end if tell application "Mail" set mailIdle to background activity count = 0 end tell if mailIdle then set senderCount to count of senderList if senderCount = 0 then set firstRun to true quit return 0 end if set sayStr to "[[volm " & voiceVolume & "]]" & "New mail:" & space if senderCount > senderCntThreshold then set sayStr to sayStr & "From " & senderCount & " different senders !" & space end if if senderCount is less than or equal to senderCntMax then -- Report the findings repeat with x in senderList set thisSender to sender of x set cnt to cnt of x set sayStr to sayStr & spokenPrefix(senderCount, cnt) & space if thisSender is " junk " then set sayStr to sayStr & "junk." & space else -- set sayStr to sayStr & "from " & pickFirstPart(thisSender) & "." & space set sayStr to sayStr & "from " & thisSender & "." & space set lastSubject to "" set said to false repeat with y in subjectList if sender of y is equal to thisSender and said is false then set thisSubject to subject of y set thisRead to status of y --if lastSubject is not equal to thisSubject and thisRead is true then -- if lastSubject is not equal to thisSubject and thisRead is false then if lastSubject is not equal to thisSubject and thisRead = 0 then --if lastSubject is not equal to thisSubject then set thisSubject to cleanSubject(thisSubject) set sayStr to sayStr & "subject " & thisSubject & "." & space set said to true end if set lastSubject to thisSubject end if end repeat end if end repeat end if if theVoice is not equal to "" then say sayStr using theVoice else say sayStr end if set senderList to {} set firstRun to true quit end if -- mailIdle countRun = countRun + 1 if countRun > maxRun then tell application "MailAnnounce" stop end tell end if return 2 -- Call again every 2 seconds... end idle on spokenPrefix(senderCount, cnt) if senderCount = 1 and cnt = 1 then return "" else return (cnt as text) end if end spokenPrefix on pickFirstPart(emailOrName) set oldDelim to AppleScript's text item delimiters if emailOrName contains "@" then set AppleScript's text item delimiters to {"@"} else set AppleScript's text item delimiters to {" "} end if return first text item of emailOrName set AppleScript's text item delimiters to oldDelim end pickFirstPart on cleanSubject(subjectText) -- todo - make arrays of search and replace strings to iterate through -- search/replace common names/emails set searchText to "re: " set replaceText to "regarding " set {oldDelim, my text item delimiters} to {my text item delimiters, searchText} try set textList to every text item of subjectText set my text item delimiters to replaceText set newText to textList as text set my text item delimiters to oldDelim on error set newText to searchText set my text item delimiters to oldDelim end try return newText end cleanSubject on quit continue quit end quit