arraysswiftstructapplescriptnsapplescript

How to correctly run AppleScript on Mail.app via NSAppleScript and parse results as a list of strings


I've the following code that I would like to use to get a list of the email accounts available within the Mail.app.

import Foundation

struct EmailAccounts {
    func getAccountNames() -> [String] {
        let appleScriptSource = """
        tell application "Mail"
            set accountDict to {}
            repeat with acc in accounts
                set accName to name of acc
                set accEmails to email addresses of acc
                set accountDict's end to {accName:accEmails}
            end repeat
            return accountDict
        end tell
        """

        var error: NSDictionary?
        var accountNames: [String] = []

        if let scriptObject = NSAppleScript(source: appleScriptSource) {
            let scriptResult = scriptObject.executeAndReturnError(&error)
            if let listDescriptor = scriptResult.coerce(toDescriptorType: typeAEList) {
                for index in 1...listDescriptor.numberOfItems {
                    if let listItemString = listDescriptor.atIndex(index)?.stringValue {
                        accountNames.append(listItemString)
                    }
                }
            }
        }

        return accountNames

    }
}

Debugging, would suggest that scriptResult.coerce(toDescriptorType: typeAEList) evaluates to nil as breakpoints set below, within the loop are not hit.

The AppleScript evaluates without a problem returning a list of account names and associated email addresses

tell application "Mail"
    set accountInfoList to {}
    repeat with acc in accounts
        set accName to name of acc
        set accEmails to email addresses of acc
        set end of accountInfoList to {accName, accEmails}
    end repeat
    return accountInfoList
end tell

Apple Script Results

Question: How can I utilise the scriptResult object to arrive at array of strings representing output obtained via AppleScript?


At the moment I'm ignoring the fact that outputs should be treated as a nested array with multiple email addresses attached to a single account, but I can deal with this minor issue later.


Solution

  • scriptResult is already a list; you cannot coerce it. Just go right ahead and start dealing with it as a list:

    for index in 1...scriptResult.numberOfItems {
        print(scriptResult.atIndex(index)?.isRecordDescriptor)
    }
    

    This will prove to you that you have a list of as many AppleScript records as there are accounts. Now go ahead and deal with your "minor issue", i.e. how to get the info out of each AppleScript record.