I tried to re-jig the applescript from these two answers, but no dice. It seems to work if you're creating contacts at the same time, but not when finding existing contacts.

tell application "Contacts"
    set thePersons to {"john@email.com"} as list
    set theGroup to group "MyGroup"
    repeat with thePerson in thePersons
        delay 0.1
        set theContact to (first person whose value of last email contains thePerson)
        add theContact to theGroup
    end repeat
end tell

The above runs without error, but nothing happens, no one is added. I'm not exactly sure what I'm doing wrong.

The goal is to produce an applescript where I can just provide a list of emails and it'll find/add them to a specified group.


This is one way to do get the syntax right for this task:

to addContactsByEmail:(e_mails as list) toNamedGroup:(group_name as text)
        local e_mails, group_name
        tell application id "com.apple.AddressBook"
                set target_group to the group named group_name
                repeat with e_mail in the e_mails
                        tell (the first person whose e_mail is in the ¬
                               value of its emails) to if exists then ¬
                               add it to the target_group
                end repeat
        end tell
end addContactsByEmail:toNamedGroup:

I've also wrapped it in a handler to be called as a re-usable code block, e.g.

my addContactsByEmail:{"foo@bar.com", "people@desks.com"} toNamedGroup:"Imaginary Friends"

You may wish to add some error-handling to cover the situations where the specified named group doesn't exist. Currently, it'll throw an error (the same as yours would), but you could either elect to exist the handler gracefully if the group doesn't exist; or to create the group automatically.

  • This works perfectly, thanks! Is it just better to reference AddressBook for this instead of the Contacts? Seems to be the main difference from my script.
    – Karric
    Aug 6 '20 at 19:44
  • One difference is that you direct your add command to the application object, whereas I directed it to the person object. That said, I don’t think that should make a huge difference. The biggest difference is your omission of the save command, which is needed to make changes permanent. But I will run your script again and tell you what transpires. I did it the first time, but have forgotten.
    – CJK
    Aug 6 '20 at 22:55
  • Two small notes: ⓵ No need to coerce a list into a list. Besides not being necessary, it’s a fairly costly operation, which is why other languages type check before re-casting, but AppleScript, if I recall, doesn’t, and will actually perform a needless coercion. ⓶ There are specific instances where a delay will be effective, and the reason why is always because the operation preceding it doesn’t return a value. Actually, it’s more accurate to say the operation is run asynchronously, so it doesn’t wait for a value to be returned. All our commands run synchronously so delays won’t help
    – CJK
    Aug 6 '20 at 23:08
  • Finally, the choice by Apple to name the application “Contacts” but assign “AddressBook” to form part of its bundle identifier (I’ll refer to this as ID) is atypical and not important. But to answer your question, I would say Yes, it is generally more reliable to reference an application by its ID than its name: ⓵ Apps get renamed all the time by developers. They even get renamed by users in Finder. IDs change less frequently as it is registered with Apple, so a ballache for the dev. Users can’t change these. ⓶ IDs registered with Apple must be unique. “Contacts” won’t be. Cont’d...
    – CJK
    Aug 6 '20 at 23:22
  • Cont’d... ⓷ The name of an app is very often locale specific. “Contacts” is called “Kontakte” in Germany. The ID is “com.apple.AddressBook” everywhere in the world. ⓸ process objects are usually named the same as the application that spawned it, but not always. It’s therefore more reliable to reference a process by the bundle identifier too, but it’s not as easy. There’s no process id ... key form, so one needs to first process whose bundle identifier = .... ⓹ Pro tip: using the app id key form avoids triggering application launches that occur using its named key form.
    – CJK
    Aug 6 '20 at 23:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .