turn an applescript into a service

the applescript outlined in email file from finder II takes selected items in the finder and attaches them to a new outgoing email message. it allows for multiple recipients from your address book and automatically adds a subject line and some basic content to the email.

there are a few ways to make that applescript accessible in the finder but the most convenient is to turn it into a service. this method is for OS X 10.6 and later — you can see a similar procedure for earlier operating systems in the post get file path of finder items.

Automator Iconapplescript services can be created through automator — the automation program that comes standard on every mac since OS X 10.4 (you’ll find it in your applications folder).

when you first open automator you’ll see this screen — choose service :
screen grab of automator startup screen

this next screen grab shows a couple of different things you need to do. in the main window on the right are two dropdowns — set the first to files or folders and the second to finder. in the search field on the left type ‘applescript’ to easily find the run applescript action. drag and drop this action into the right window :
screen grab of automator with service being built

then paste your applescript into that action window — you can entirely replace the default script. this is what it should look like after you hit the compile button (hammer) :
screen grab of automator service window with applescript in place

save that out and you’re done. now, whenever you want to email something from the finder just select it and right-click — you’ll see your service near the bottom of the contextual menu :
screen grab showing the service as a contextual menu item

you can also activate it under finder > services :
screen grab of services menu

under that menu you can also access the services preferences. this allows you to even set a keyboard shortcut for your new handy service :
screen grab of services preferences window

of course, services aren’t just restricted to running your applescripts. investigate the full power of automator … and get grunting.

macgrunt icon

Advertisements

email file from finder II

the previous post — email file from finder — showed how to use applescript to quickly attach a selected finder item to an email — adding a recipient, subject and basic content along the way. this post will show how to adapt that script to allow for multiple attachments and multiple recipients.

here’s the original script :

set mgPeople to {}
set mgFirsts to {}
set mgAddresses to {}

tell application "Address Book"
  repeat with mgPerson in people
    tell mgPerson
      repeat with mgEmail in emails
        copy name to the end of mgPeople
        copy first name to the end of mgFirsts
        copy value of mgEmail to the end of mgAddresses
      end repeat
    end tell
  end repeat
end tell

-- thanks to Mark J. Reed 
-- http://lists.apple.com/archives/applescript-users/2007/Mar/msg00086.html
set text item delimiters of AppleScript to (ASCII character 10)
set mgSortedPeople to paragraphs of (do shell script "echo " & quoted form of (mgPeople as string) & "| sort  -d -f")
set text item delimiters of AppleScript to ""
-------------

choose from list mgSortedPeople with prompt "who you emailing then?"
if result is not false then
  set mgChosenOne to item 1 of result
else
  error number -128
end if

repeat with x from 1 to count of mgPeople
  if item x of mgPeople = mgChosenOne then
    set mgFirstName to item x of mgFirsts
    set mgChosenEmail to item x of mgAddresses
  end if
end repeat

tell application "Finder"
  set mgSelection to the selection
  set text item delimiters of AppleScript to ":"
  if class of (item 1 of mgSelection) is folder then
    set mgSubject to text item -2 of ((item 1 of mgSelection) as string)
    set mgContent to "Hi " & mgFirstName & return & return & "Here's that folder we were talking about." & return & return
  else
    set mgSubject to text item -1 of ((item 1 of mgSelection) as string)
    set mgContent to "Hi " & mgFirstName & return & return & "Here's the file you're waiting for." & return & return
  end if
  set text item delimiters of AppleScript to "."
  set mgSubject to text item 1 of mgSubject
  set text item delimiters of AppleScript to ""
end tell

tell application "Mail"
  activate
  set mgMessage to make new outgoing message with properties {subject:mgSubject, content:mgContent, visible:true}
  tell mgMessage
    make new to recipient with properties {name:mgChosenOne, address:mgChosenEmail}
    make new attachment with properties {file name:(mgSelection as alias)} at after last paragraph of content
    save
  end tell
end tell

that script first creates three lists — names, first names and email addresses. the list of first names was used to create the salutation in the email (“Hi whoever”). but this script allows for multiple recipients so the salutation will change (in this script we’ll use “Hi all”). so, the start of the script will be stripped back to this :

set mgPeople to {}
set mgAddresses to {}

tell application "Address Book"
  repeat with mgPerson in people
    tell mgPerson
      repeat with mgEmail in emails
        copy name to the end of mgPeople
        copy value of mgEmail to the end of mgAddresses
      end repeat
    end tell
  end repeat
end tell

-- thanks to Mark J. Reed 
-- http://lists.apple.com/archives/applescript-users/2007/Mar/msg00086.html
set text item delimiters of AppleScript to (ASCII character 10)
set mgSortedPeople to paragraphs of (do shell script "echo " & quoted form of (mgPeople as string) & "| sort  -d -f")
set text item delimiters of AppleScript to ""
-------------

the next thing we need to do is allow the user to select multiple email recipients. that’s as simple as changing the end of that choose from list command. we also need to change the way we capture that data — it’s no longer a list with only one item :

choose from list mgSortedPeople with prompt "who you emailing then?" with multiple selections allowed
if result is not false then
  set mgChosenOnes to result
else
  error number -128
end if

as per standard mac functionality, you can select multiple items in the dialog by holding down the command key :
screen grab of choose from list dialog with multiple recipients selected

we’re going to dump the next repeat loop from the original script — we’ll integrate that functionality once we start talking to Mail. here’s the new code we need for addressing the finder. this time we’re going to capture the name of the folder containing the finder selection to use as our subject line :

tell application "Finder"
  set mgSelection to the selection
  set text item delimiters of AppleScript to ":"
  if class of (item 1 of mgSelection) is folder then
    set mgSubject to text item -3 of ((item 1 of mgSelection) as string)
  else
    set mgSubject to text item -2 of ((item 1 of mgSelection) as string)
  end if
  set text item delimiters of AppleScript to ""
end tell

the original script allowed for one attachment and one recipient, so the last portion of the script — the bit that created the actual email — was quite simple. with this version we need two repeat loops — one to process the multiple recipients and one to process the multiple attachments :

tell application "Mail"
  activate
  set mgContent to "Hi all" & return & return & "Please find attached ..." & return & return
  set mgMessage to make new outgoing message with properties {subject:mgSubject, content:mgContent, visible:true}
  tell mgMessage
    repeat with mgChosenOne in mgChosenOnes
      repeat with x from 1 to count of mgPeople
        if item x of mgPeople = (mgChosenOne as string) then
          set mgChosenEmail to item x of mgAddresses
          make new to recipient with properties {name:mgChosenOne, address:mgChosenEmail}
        end if
      end repeat
    end repeat
    repeat with mgitem in mgSelection
      make new attachment with properties {file name:(mgitem as alias)} at after last paragraph of content
    end repeat
    save
  end tell
end tell

screen grab of email created by the script

your homework for this week is to come up with a way to make the salutation personal if only one recipient is selected (eg. “Hi John”) but generic if multiple recipients are selected (eg. “Hi all”).

next time we’ll look again at how to turn this script into a service for easy accessibility from within the finder.

macgrunt icon

email file from finder

InDesign scripting : lesson 22 showed an applescript that exports a pdf from InDesign and attaches it to an email — adding a subject and recipient along the way. here’s a variation that lets you email an existing file directly from the finder. the previous script used a predefined list of email addresses — this one accesses your address book.

the first part of the script compiles three lists — names, first names and email addresses. we start by creating three empty lists before moving on to copying the relevant data into those lists. then we use the choose from list command to create a UI for the user to make a selection from. mgPeople is the list of names for people in your address book who have an email address :

set mgPeople to {}
set mgFirsts to {}
set mgAddresses to {}

tell application "Address Book"
  repeat with mgPerson in people
    tell mgPerson
      repeat with mgEmail in emails
        copy name to the end of mgPeople
        copy first name to the end of mgFirsts
        copy value of mgEmail to the end of mgAddresses
      end repeat
    end tell
  end repeat
end tell

choose from list mgPeople

you’ll notice the list is in a crazy order. that’s because the list is in ID order — the order in which the contacts were entered into your address book :
screen grab of initial choose from list dialog

so, to make things a leetle easier, we need to reorder the list alphabetically. thanks to mark j. reed over at the apple mailing lists for the shell script :

set mgPeople to {}
set mgFirsts to {}
set mgAddresses to {}

tell application "Address Book"
  repeat with mgPerson in people
    tell mgPerson
      repeat with mgEmail in emails
        copy name to the end of mgPeople
        copy first name to the end of mgFirsts
        copy value of mgEmail to the end of mgAddresses
      end repeat
    end tell
  end repeat
end tell

-- thanks to Mark J. Reed 
-- http://lists.apple.com/archives/applescript-users/2007/Mar/msg00086.html
set text item delimiters of AppleScript to (ASCII character 10)
set mgSortedPeople to paragraphs of (do shell script "echo " & quoted form of (mgPeople as string) & "| sort  -d -f")
set text item delimiters of AppleScript to ""
-------------

choose from list mgSortedPeople with prompt "who you emailing then?"
if result is not false then
  set mgChosenOne to item 1 of result
else
  error number -128
end if

that last part captures the result of the dialog into a variable (mgChosenOne) or, if the user hits cancel instead, stops the script (error number -128). this is needed because of a quirk of the choose from list command — the cancel button doesn’t actually cancel the process it just returns a ‘false’ result. the observant will notice we’ve added our own prompt to this version of the dialog. you can also add a title to that top bar as well if you like :
screen grab of alphabetisied choose from list dialog

the next bit simply matches up the chosen recipient with their first name and email address and captures those into variables too :

repeat with x from 1 to count of mgPeople
  if item x of mgPeople = mgChosenOne then
    set mgFirstName to item x of mgFirsts
    set mgChosenEmail to item x of mgAddresses
  end if
end repeat

then we need to get a reference to the selected object in the finder. and we set a subject and content for the email message. you can see that we’re checking to see if the selected object is a file or folder first, then setting the subject and content accordingly. the subject will be the name of the file or folder and the content is our own chosen verbage :

tell application "Finder"
  set mgSelection to the selection
  set text item delimiters of AppleScript to ":"
  if class of (item 1 of mgSelection) is folder then
    set mgSubject to text item -2 of ((item 1 of mgSelection) as string)
    set mgContent to "Hi " & mgFirstName & return & return & "Here's that folder we were talking about." & return & return
  else
    set mgSubject to text item -1 of ((item 1 of mgSelection) as string)
    set mgContent to "Hi " & mgFirstName & return & return & "Here's the file you're waiting for." & return & return
  end if
  set text item delimiters of AppleScript to "."
  set mgSubject to text item 1 of mgSubject
  set text item delimiters of AppleScript to ""
end tell

the last part creates the email based on all the bits and pieces we’ve put together in the other parts of the script. this is how you would do it for Mail. see InDesign scripting : lesson 22 to see how to do it for Outlook. for other email software, consult your applescript dictionary for that program :

tell application "Mail"
  activate
  set mgMessage to make new outgoing message with properties {subject:mgSubject, content:mgContent, visible:true}
  tell mgMessage
    make new to recipient with properties {name:mgChosenOne, address:mgChosenEmail}
    make new attachment with properties {file name:(mgSelection as alias)} at after last paragraph of content
    save
  end tell
end tell

put all those bits together, customise it to your particular way of working, and you’ve got yourself a handy little timesaver. there are a number of ways to activate a script like this, but the easiest is to turn it into a service so that you can activate the script with a right-click or keyboard shortcut. see get file path of finder items which shows how to do this through automator.

screen grab of email created by the script

the next post will show how to convert this script to allow for multiple attachments and multiple recipients.

til then, keep grunting.

macgrunt icon

iCal and address book

what in the name of hideous monstrosities was apple thinking when they shipped lion with those fugly interfaces for iCal and address book? that faux baby-poo leather and torn page look is the naffest thing apple have done since that white crumb-catcher keyboard.

the styling for the app must have been outsourced to some executive’s pampered, brain-damaged, drug-addled nephew.

thankfully it’s easy to fix — to ease your troubled eyeballs, just replace all the graphics in the app package with new ones.

you can find aluminium-look graphics and instructions on how to install them at MacNix. if you appreciate how easy it is — flick MacNix a donation.

screen grab of iCal before and after updating graphics

macgrunt icon

deleting empty folders

some workflows involve creating standard sets of job folders at the beginning of a project and then going through and cleaning out any unused folders at the end. this is a good way to standardise archiving procedures but it can also be tedious to clean up once the project is done. this post shows how to easily delete empty folders using applescript.

thanks to xander at cadcoder (sorry this link seems to be broken at the moment — Aug 2013) for the basic structure of the shell command.

Applescript Icon to follow along, copy and paste the script examples into applescript editor (found in applications > utilities) or, for older OS versions, script editor (applications > applescript). we’re going to set this one up as a droplet (so you’ll save it from script editor as an application). you can save a droplet to your desktop or drag it to your sidebar for easy access. to run the script just drag and drop a folder onto the droplet’s icon.

the basic form of the script goes like this :

on open mgItem
  do shell script "cd " & quoted form of POSIX path of mgItem & " && find . -type d -empty -delete;"
end open

in the shell, a folder is known as a directory (d). the first part of the command changes the current directory (cd) to our dropped folder. then it performs a search of that folder (find) for empty subfolders (-type d -empty) and deletes them. simple.

this works a treat — most of the time. but macs have these dastardly hidden files, the most common of which are the good old .DS_Store files which help the finder do its thing. a folder containing nothing but a .DS_Store file looks empty, but as far as the shell is concerned, it’s not.

so, here’s a variation to deal with that issue — first delete any .DS_Store files, then delete empty folders :

on open mgItem
  do shell script "cd " & quoted form of POSIX path of mgItem & " && find . -name .DS_Store -delete; find . -type d -empty -delete;"
end open

ok, that’s better. but to make the droplet a little more user-friendly, we should ensure it can handle multiple dropped folders — rather than having to drop them one at a time :

on open mgItems
  repeat with mgItem in mgItems
    do shell script "cd " & quoted form of POSIX path of mgItem & " && find . -name .DS_Store -delete; find . -type d -empty -delete;"
  end repeat
end open

and to make it more robust, it should not have a conniption if we inadvertently drop files instead of, or as well as, folders :

on open mgItems
  repeat with mgItem in mgItems
    set mgItem to mgItem as alias
    tell application "System Events" to set theClass to get class of item (mgItem as string)
    
    if (theClass as string) contains "cfol" then
      do shell script "cd " & quoted form of POSIX path of mgItem & " && find . -name .DS_Store -delete; find . -type d -empty -delete;"
    end if
    
  end repeat
end open

that’s about it — super fast, super easy way to clean out any unused folders.

for those interested in this sort of thing…
applescript droplet icon when an applescript is saved as a droplet, its icon includes a downwards pointing arrow. the on open mgItems line at the start of this script is what allows the saved application to run as a droplet. without that on open command you’d need to find some other way to reference the folders to be processed. renaming finder items shows a couple of other ways you could do this.

macgrunt icon