My script correctly creates mailto: URLs in the form:
mailto:Wile Coyote<beepbeeb@acme.com>?&subject=Happy 57th Birthday 🎈&body=Wile:\r\n\r\nI hope that you have a special celebration planned for today.\r\n\r\n- roadRunner
However, when I use open location to launch it in the (Chrome) web interface to Gmail, the emoji in the subject is converted to ?
I presume this conversion is due to open location not encoding UTF-8 characters correctly. (If I simply copy/paste the above string into the Chrome address bar, the resulting Gmail message subject contains the emoji.)
How should I open this URL within an AppleScript? Is there a way for open location to encode it correctly? If not, do I need to use a shell script to open it?
Would someone please share a code snippet or URL to some examples?
-- Created 2016-04-19 by Takaaki Naganoya
-- Modified 2022-06-05 by Takaaki Naganoya
-- 2022 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
property NSURLQueryItem : a reference to current application's NSURLQueryItem
property NSURLComponents : a reference to current application's NSURLComponents
property NSMutableDictionary : a reference to current application's NSMutableDictionary
set aBaseURL to "mailto:beepbeeb@acme.com"
set aRec to {subject:"Happy 57th Birthday 🎈", body:"Wile:
I hope that you have a special celebration planned for today.
- roadRunner"}
set urlRes to retNSURLwithParams(aBaseURL, aRec) of me
current application's NSWorkspace's sharedWorkspace()'s openURL:urlRes
on retNSURLwithParams(aBaseURL as string, aRec as record)
set aDic to NSMutableDictionary's dictionaryWithDictionary:aRec
set aKeyList to (aDic's allKeys()) as list
set aValList to (aDic's allValues()) as list
set aLen to length of aKeyList
set bLen to length of aValList
if aLen is not equal to bLen then return false
set qList to {}
repeat with i from 1 to aLen
set aName to (contents of item i of aKeyList) as string
set aVal to (contents of item i of aValList) as string
set the end of qList to (NSURLQueryItem's queryItemWithName:aName value:aVal)
end repeat
set aComp to NSURLComponents's alloc()'s initWithString:aBaseURL
aComp's setQueryItems:qList
return aComp's |URL|()
end retNSURLwithParams
The URL standard states that only US ASCII characters can appear in a URL. Converting your Unicode Emoji characters to UTF-8 is not sufficient. You need to escape the UTF-8 character codes as hex bytes (%##).
Pure AppleScript is not the best tool for this sort of thing. You could do this with ASObjC or you could shell out to perl or python to do the conversion.
@Piyomaru 's code is a good place to start with ASObjC.
(and it might be easier to do the the whole thing in osascript -l JavaScript, or in Script Editor with the language selector at top left set to JavaScript in lieu of AppleScript)
I wrote a perfectly cromulent set of AppleScript standard libraries some years back. The Web library wraps the ObjC URL APIs in friendly AppleScript-style commands. The commands to use when assembling URLs:
encode URL characters
join URL query string
join URL
Examples are included in the library’s dictionary.
WRT calling out to Perl/Python/JavaScript/etc, to paraphrase Zawinski:
Some people, when confronted with a problem, think “I know, I’ll use ${TECHNOLOGY}.” Now they have two problems.
Or, alternately:
“Yo Dawg i herd you like character escapes so we put a character escapes in yo character escapes…”
Shelling out to Python et al is really a non-starter nowadays as Apple no longer bundles the P-languages as standard in macOS. (Even when they were present, going through do shell script and multiple layers of character escaping was non-trivial to get right.)
As for JXA, though still included in macOS (Dog knows why), that corpse walks in a small sad world of Fail all of its own, and trying to use it for non-trivial work is just a miserable exercise in futility. (Honestly, if you want to use JavaScript for anything, run—don’t walk—to Node.js.)
Calling into ObjC’s NSURL APIs is the one good and sensible solution here. There’s no contest. If OP doesn’t want to deal with ASOC directly (it is a chore), there is as I say already a Web library that wraps all the ObjC ugliness behind familiar friendly AppleScript syntax.
…
It’s a real pity most of the AS community never really “got” libraries. While AppleScript, like JavaScript, will never be a good language in itself, having a popular populated repository of third-party libraries a-la npm or PyPI goes a long way to minimizing the pain of boring generic crapwork, so you can focus on doing what the AppleScript language is genuinely good at (automating Mac apps) instead of wading through the stuff that it sucks at (everything else).
Indeed. My RegexAndStuffLib contains commands for this stuff too:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use script "RegexAndStuffLib" version "1.0.7"
set theSubject to "Happy 57th Birthday 🎈"
set theBody to "Wile:
I hope that you have a special celebration planned for today.
- roadRunner"
set theSubject to percent encode theSubject
set theBody to percent encode theBody
The command also has parameters to customise the encoding according to component being encoded.
-- Created 2017-02-23 by Takaaki Naganoya
-- Modified 2022-06-06 by Takaaki Naganoya
-- 2022 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
set shareItems to {"Wile:
I hope that you have a special celebration planned for today.
- roadRunner", "Footer?"}
set aRecipients to {"Wile Coyote<beepbeeb@acme.com>"}
set aSubject to "Happy 57th Birthday 🎈"
set aParam to {myShares:shareItems, myRecipients:aRecipients, mySubject:aSubject}
my performSelectorOnMainThread:"composeAnEmail:" withObject:aParam waitUntilDone:true
--my composeAnEmail:aParam--For debugging with Script Editor by using command-control-r
on composeAnEmail:aParamObj
set aRecipients to (myRecipients of aParamObj) as list
set aSubject to (mySubject of aParamObj) as string
set aShareItems to (myShares of aParamObj) as list
set aService to current application's NSSharingService's sharingServiceNamed:(current application's NSSharingServiceNameComposeEmail)
aService's setDelegate:me
aService's setRecipients:(aRecipients)
aService's setSubject:(aSubject)
aService's performWithItems:(aShareItems)
end composeAnEmail:
I used Piyomaru’s script to create a new text message instead of a new email. The script succeeded relatively well with only two errors.
1, subject value did not show
2. Messages erred with either dialog
a, mail system at host bbtpnj33wzwvetm-c-nk-x-00-sms-01.vtext.com expanded the recipient incorrectly
b. Message Send Failure
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions
set shareItems to {"Wile:
I hope that you have a special celebration planned for today.
🤸🏼♀️
- roadRunner"}
set aRecipients to {"Wile Coyote<beepbeeb@acme.com>"}
set aSubject to "Happy 57th Birthday 🎈"
set aParam to {myShares:shareItems, myRecipients:aRecipients, mySubject:aSubject}
my performSelectorOnMainThread:"composeAMessage:" withObject:aParam waitUntilDone:true
on composeAMessage:aParamObj
set aRecipients to (myRecipients of aParamObj) as list
set aSubject to (mySubject of aParamObj) as string
set aShareItems to (myShares of aParamObj) as list
set aService to current application's NSSharingService's sharingServiceNamed:(current application's NSSharingServiceNameComposeMessage)
aService's setDelegate:me
aService's setRecipients:(aRecipients)
aService's setSubject:(aSubject)
aService's performWithItems:(aShareItems)
end composeAMessage:
I would be interested in any solutions to correct those two Message Sharing Service errors
That’s a link that’s live in Script Debugger’s Dictionary view, but becomes meaningless when saved as a PDF. The PDF is a convenience – you’re better off viewing the dictionary in Script Debugger.