Lately I was working on an AppleScript that sends personalized bulk email along with an individual PDF attachment to simplify and automate the coming christmas mailing.
But while creating the small application I soon ran into an annoying problem: How can I access the eMail addresses chosen in the Distribution List editor of the Mac OS X Address Book with AppleScript? Yes, I can get all persons of an Address Book Group and I can also get all their eMail addresses. But no, unfortunately I cannot easily get the Distribution List eMail addresses…
At first I was very frustrated. Moreover I was very jelous of Christian Fries, because his excellent (and free) Serial Mail software is obviously able to access the Distribution List eMail addresses But his software is not written entirely in AppleScript, he also uses Objective-C. And this fact pointed me to Apple’s Address Book Programming Guide where I finally found the solution to my problem!
Now I was able to write a small Python helper script utilizing PyObjC’s AddressBook framework that simply returns the Distribution List eMail addresses of a certain Address Book Group to the calling AppleScript. Happiness came back!
And it really works like a charm here on Mac OS X 10.5. And it even works without opening the Address Book at all. If you are interested in the script code or want to give it a try on your Mac, then I invite you to download the following sample script, which can also be studied in the Script Editor:
ABG Distribution List Emails - Get Distribution List email addresses from an Address Book Group (ca. 37 KB)
Please note that the AppleScript requires Mac OS X 10.5 Leopard. Or in case you are using an earlier incarnation of our beloved operating system, you need to manually install PyObjC on your Mac.
The sample script WILL open the Address Book at the end, but just to retrieve certain values for the found persons (name, company, etc.). This can be avoided by further customizing the Python script.
Important: Opening and saving the below script code in Script Editor won’t result in a usable AppleScript! That is because the AppleScript internally relies on a Python helper script, which is located inside its Script bundle. Therefor please download the complete script here.
-- author: Martin Michel
-- created: 02.08.2008
-- required:
-- ¢ Mac OS X 10.5 Leopard
-- tested on:
-- ¢ Intel- and PowerPC-based Macs
-- This AppleScript let's you choose an Address Book Group and then displays the email address for every person,
-- which is used when the person is contacted through the chosen group (distribution list email address).
-- As AppleScript itself cannot access this information, a Python script utilizing the PyObjC AddressBook
-- framework is used as a helper script.
-- The script can come in handy when you want to create a custom serial mailing :)
property mytitle : "ABG Distribution List Emails"
-- I am called when the user opens the script with a doubleclick
on run
try
-- asking the user to choose an address book group
set chosenabgrouprecord to my chooseabgroup()
-- no address book groups availabe or user canceled
if chosenabgrouprecord is missing value then
return
end if
-- unique id of the chosen address book
set abgroupid to item 1 of chosenabgrouprecord
-- name of the chosen address book
set abgroupname to item 2 of chosenabgrouprecord
-- getting the distribution list emails of the chosen adress book group
set dlistrecord to my getdlistemails(abgroupid)
-- no members available in this address book group
if dlistrecord is missing value then
return
end if
-- unique id of the member/person
set personids to item 1 of dlistrecord
-- email address used when contacting the person/member through the chosen group
set dlistemails to item 2 of dlistrecord
set countpersonids to length of personids
-- this is just a demo that displays the found distribution list email address
-- for all contacts in the chosen group
repeat with i from 1 to countpersonids
set personid to item i of personids
set dlistemail to item i of dlistemails
set {personfname, personlname, personorganization} to my getpersondata(personid)
tell me
activate
display dialog "AB Group: " & abgroupname & return & "Member: " & personfname & space & personlname & return & "Company: " & personorganization & return & "Email: " & dlistemail with title mytitle
end tell
end repeat
-- catching unexpected errors
on error errmsg number errnum
-- ignoring 'User canceled'-error
if errnum is not equal to -128 then
my dsperrmsg(errmsg, errnum)
end if
end try
end run
-- I am returning a list containing the person's first name, last name and organization for the given person id
on getpersondata(personid)
tell application "Address Book"
set personobj to item 1 of (every person whose id is personid)
set personfname to (first name of personobj) as Unicode text
if personfname is "missing value" then
set personfname to ""
end if
set personlname to (last name of personobj) as Unicode text
if personlname is "missing value" then
set personlname to ""
end if
set personorganization to (organization of personobj) as Unicode text
if personorganization is "missing value" then
set personorganization to ""
end if
end tell
return {personfname, personlname, personorganization}
end getpersondata
-- I am asking the user to choose an Address Book Group
-- I return a list containing the id and name of the chosen Address Book Group
-- or missing value in case no groups are available or the user cancels the dialog
on chooseabgroup()
set pyscriptpath to POSIX path of (((path to me) as Unicode text) & "Contents:Resources:Scripts:abx.py")
set command to "/usr/bin/python " & quoted form of pyscriptpath & " getgroups"
set shelllines to paragraphs of (do shell script command)
if shelllines is {} then
set errmsg to "Your Adress Book does not contain any groups yet."
my dsperrmsg(errmsg, "--")
return missing value
end if
-- the Python script returns tab delimited lines containing the
-- ids and names of the address book groups, e.g.:
-- 181C5BBB-FE2A-419F-AD6E-D2A92A678B66:ABGroup Hotels
-- FF2EEE74-9F40-11D8-BC68-000A95971BFE:ABGroup Restaurants
-- .
set abgroupnames to {}
set abgroupids to {}
repeat with shelline in shelllines
set olddelims to AppleScript's text item delimiters
set AppleScript's text item delimiters to {tab}
set {abgroupid, abgroupname} to text items of shelline
set AppleScript's text item delimiters to olddelims
set abgroupids to abgroupids & abgroupid
set abgroupnames to abgroupnames & abgroupname
end repeat
-- we have to number the address book group names, so that we can later choose/return the
-- corresponding address book group id
set menuitems to {}
set counter to 0
repeat with abgroupname in abgroupnames
set counter to counter + 1
if counter < 10 then
set strcounter to ("0" & counter) as Unicode text
else
set strcounter to (counter as Unicode text)
end if
set menuitems to menuitems & (strcounter & " " & abgroupname)
end repeat
-- finally asking the user to choose an address book group
choose from list menuitems with prompt "Please choose an Address Book Group:" OK button name "Select" cancel button name "Cancel" with title mytitle without empty selection allowed and multiple selections allowed
set usrchoice to result
if usrchoice is not false then
set chosenmenuitem to (item 1 of usrchoice)
set spaceoffset to offset of " " in chosenmenuitem
set idx to ((characters 1 through 2 of chosenmenuitem) as Unicode text) as integer
return {item idx of abgroupids, item idx of abgroupnames}
else
return missing value
end if
end chooseabgroup
-- I am returning a list containing the person ids and distribution list emails for a given address book id
on getdlistemails(abgroupid)
set pyscriptpath to POSIX path of (((path to me) as Unicode text) & "Contents:Resources:Scripts:abx.py")
set command to "/usr/bin/python " & quoted form of pyscriptpath & " getdlistemails " & quoted form of abgroupid
set shelllines to paragraphs of (do shell script command)
if shelllines is {} then
set errmsg to "The chosen Address Book Group does not contain any members."
my dsperrmsg(errmsg, "--")
return missing value
end if
set personids to {}
set dlistemails to {}
repeat with shelline in shelllines
set olddelims to AppleScript's text item delimiters
set AppleScript's text item delimiters to {tab}
set {personid, dlistemail} to text items of shelline
set AppleScript's text item delimiters to olddelims
set personids to personids & personid
set dlistemails to dlistemails & dlistemail
end repeat
return {personids, dlistemails}
end getdlistemails
-- I am displaying error messages to the user
on dsperrmsg(errmsg, errnum)
tell me
activate
display dialog "Sorry, an error occured:" & return & return & errmsg & return & "(" & errnum & ")" buttons {"OK"} default button 1 with icon stop giving up after 20 with title mytitle
end tell
end dsperrmsg