Correctly using NSAppleScript for Mail.app plugin

Context

  • I'm working on a Mail.app plugin. I would like to disseminate plugin via AppStore.
  • I'm interested in exposing a functionality to user enabling user to choose if plugin should apply to all or selected email account.
  • My intention is to use AppleScript to get a list of available email accounts and expose the list to the end-user via SwiftUI

Sourcing account information

Apple Script

I'm using the following AppleScript

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

The above generates expected results when executed using Script Editor.

Swift Implementation

This is still incomplete but shows the overall plan.

//
//  EmailAccounts.swift
import Foundation

enum EmailScriptError: Error {
    case scriptExecutionError(String)
}

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] = []

        // Create script object, exit if fails
        guard let scriptObject = NSAppleScript(source: appleScriptSource) else {
            return nil
        }

        // Execute script and store results, nil on error
        let scriptResult = scriptObject.executeAndReturnError(&error)
        if error != nil { return nil }

        // Iterate over results
        for index in 0...scriptResult.numberOfItems {
            if let resultEntry = scriptResult.atIndex(index) {
                if let resultString = resultEntry.stringValue {
                   // Process result handling
                   // accountNames.append(resultString)
                }
            }

        }

        return accountNames

    }
}

Questions

  1. Most important one, can I deploy the App on the App Store and use NSAppleScript as shown above?
  2. If yes can I use the script in the manner shown above or will I need to store the script in User > Library > Application Scripts location and source it from there. This is outlined in the Scripting from a Sandbox article by Craig Hockenberry, which I cannot link due to being hosted within a not-permitted domain.
  3. If yes what entitlements I need to give to the target.
  4. I understand that I wouldn't be able to use ScriptingBridge, which feels more robust but wouldn't permit me to deploy the app on the AppStore.
  5. My key objective is to programatically identify mail accounts available to Mail.app, if there is a wiser / easier way of doing that I would be more than receptive.
Answered by DTS Engineer in 808850022

Let’s tackle you big picture question first and then come back to the details:

can I deploy the App on the App Store and use NSAppleScript as shown above?

Probably not.

I don’t work for App Review, and they’re the only folks who can give you definitive answers about what is or isn’t allowed on the store. However:

  • When you use NSAppleScript, the Apple events originate in your process.

  • For a sandboxed process to send arbitrary Apple events, it must be signed with the com.apple.security.temporary-exception.apple-events temporary exception entitlement.

  • My experience is that App Review only approves the use of such entitlement is exceptional circumstances, for example, to work around a sandbox bug on older systems where the bug is fixed on the latest system.

If you want a more definitive answer, you’ll need to talk to App Review directly.

will I need to store the script in User > Library > Application Scripts location and source it from there.

This mechanism is designed to support attachability. See this post for my thoughts on that topic.


And finally a couple of random comments:

which I cannot link

You can, but you have to do it in the clear. See tip 14 in Quinn’s Top Ten DevForums Tips.

I understand that I wouldn't be able to use ScriptingBridge

IME Scripting Bridge is anything but robust. However, it’s irrelevant to this discussion. Scripting Bridge is just a different way to send Apple events, but what matters is the Apple events that get sent and the process that they get sent from. There’s no difference between Scripting Bridge and NSAppleScript is that respect.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Accepted Answer

Let’s tackle you big picture question first and then come back to the details:

can I deploy the App on the App Store and use NSAppleScript as shown above?

Probably not.

I don’t work for App Review, and they’re the only folks who can give you definitive answers about what is or isn’t allowed on the store. However:

  • When you use NSAppleScript, the Apple events originate in your process.

  • For a sandboxed process to send arbitrary Apple events, it must be signed with the com.apple.security.temporary-exception.apple-events temporary exception entitlement.

  • My experience is that App Review only approves the use of such entitlement is exceptional circumstances, for example, to work around a sandbox bug on older systems where the bug is fixed on the latest system.

If you want a more definitive answer, you’ll need to talk to App Review directly.

will I need to store the script in User > Library > Application Scripts location and source it from there.

This mechanism is designed to support attachability. See this post for my thoughts on that topic.


And finally a couple of random comments:

which I cannot link

You can, but you have to do it in the clear. See tip 14 in Quinn’s Top Ten DevForums Tips.

I understand that I wouldn't be able to use ScriptingBridge

IME Scripting Bridge is anything but robust. However, it’s irrelevant to this discussion. Scripting Bridge is just a different way to send Apple events, but what matters is the Apple events that get sent and the process that they get sent from. There’s no difference between Scripting Bridge and NSAppleScript is that respect.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

This is great, thank you very much for the comprehensive answer.

Correctly using NSAppleScript for Mail.app plugin
 
 
Q