3
votes

I have been attempting to create a JavaScript for Automation script to send an iMessage via the Messages app on Yosemite 10.10.2 (the end goal to write a solution to allow backoffice tasks to iMessage failure statuses etc.).

The script executes through without error in Script Editor, however no message is sent and nothing shows or happens in Messages.app. Although my service and buddy below are obfuscated, my script with the real values retrieves the correct service and buddy (as verified by doing a messages.displayAlert() for both the service and buddy name). The only output I get from the script is an "undefined" for the service.send() which I assume is correct since that method has a void return type). This script below is what I've been unsuccessfully trying to get working:

messages = Application('Messages');

service = messages.services["E:foo@bar.com"];
buddy = service.buddies["+61nnnnnnnnn"]

service.send({
    send: "Hello World", 
    to: buddy
}); 

The equivalent AppleScript script (below) successfully works:

tell application "Messages"
    send "Hello World" to buddy "+61nnnnnnnnn" of service "E:foo@bar.com"
end tell
3

3 Answers

5
votes

Short answer: JXA is made of Lame and Fail.

...

Long answer:

When JXA runs your service.send(...) command, it should raise a "bad parameter" error, since the send command does not have a keyword parameter named send. The "Hello World" string should be passed as the send command's direct parameter, not as a keyword parameter.[1]

Instead, JXA ignores the error, sends off a malformed event, and leaves you scratching your head when it all fails silently. I'd suggest filing a bug report, but I sent the AS team a ton of issues and a nearly-complete reference implementation after WWDC'14 and they ignored us, so YMMV.

Incidentally, the elements[NAME] syntax is another misfeature that should be disouraged/avoided. a[b] and a.b are synonymous in JavaScript, which means JXA cannot reliably distinguish between keys that represent element names (e.g. documents['untitled']) and keys that represent element attributes (e.g. documents['text']). To construct by-name specifiers safely, use elements.byName(NAME). Or, heck, just stick to AppleScript, which is the only supported solution that actually speaks Apple events right.

--

[1] Yeah, Script Editor's dictionary can be a bit misleading here because it still shows commands in AppleScript-style syntax instead of formatting them appropriately for JS. (The whole thing's so half-baked and amateurish, I'd be honestly embarrassed for the AS team if I wasn't so pissed at them screwing up what was a solved problem in the first place.)

2
votes

Based on http://gwfrontiers.blogspot.nl/2015/01/javascript-for-automation-of-messages.html

with (Application("Messages")) { 
    send("Hey", {to: services["E:johndoe@icloud.com"].buddies["someone@somewhere.com"]}) 
}

The buddies parameter is the e-mail address or phone number you want to send it to. The johndoe@icloud.com is the (in this case) iMessage service name. Pick from:

services = Application("Messages").services();
for (var i in services) console.log(services[i].name());
1
votes

You need to call the send method on your messages instance, not service. Like this: messages.send("hello", {to: buddy}) Also, the message you're sending should be a top level parameter as in my example above.