• Did you order new AirTags? We've opened a dedicated AirTags forum.

Aouttier

macrumors member
Original poster
Mar 3, 2016
40
0
Belgium
I have a rtf-file with the text I often have to send by mail. Some words have to be replaced by specific words depending on the recipient (but that is not my question :)). Some words are in bold (because they are more important),...

I want to write an AppleScript, which copies the text from the file into a new mail. But, the formatting of my text is always lost, what ever I try. the last thing I have is:
AppleScript:
set textB to ((path to desktop as Unicode text) & "textB.rtf")

tell application "TextEdit"
    open file textB   
    set theContent to the text of document 1
end tell

tell application "Mail"
    tell (make new outgoing message with properties {subject:"test", content:theContent, visible:true})
    end tell
end tell

I have already a working AppleScript with System Events and keystroke,... but now, with the lockdown I have time to look for a more elegant script (since, when running the script, I press on a key my script is going down the tubes)
 

Red Menace

macrumors 6502
May 29, 2011
492
175
Colorado, USA
You can use Cocoa's NSSharingService via some AppleScriptObjC to compose a Mail message from the RTF file, for example:
AppleScript:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

on run -- needs to run on main thread
    if current application's NSThread's isMainThread() as boolean then
        doStuff()
    else
        my performSelectorOnMainThread:"doStuff" withObject:(missing value) waitUntilDone:true
    end if
end run

on doStuff()
    set theFile to ((path to desktop folder as text) & "textB.rtf")
    set fileData to current application's NSData's dataWithContentsOfFile:(POSIX path of theFile)
    set {attrString, attributes} to current application's NSAttributedString's alloc()'s initWithRTF:fileData documentAttributes:(reference)
    if attrString is missing value then error "Unable to read RTF file"
    tell (current application's NSSharingService's sharingServiceNamed:"com.apple.share.Mail.compose") to performWithItems:{attrString}
end doStuff
 
Comment

Aouttier

macrumors member
Original poster
Mar 3, 2016
40
0
Belgium
You can use Cocoa's NSSharingService via some AppleScriptObjC to compose a Mail message from the RTF file, for example:
AppleScript:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

on run -- needs to run on main thread
    if current application's NSThread's isMainThread() as boolean then
        doStuff()
    else
        my performSelectorOnMainThread:"doStuff" withObject:(missing value) waitUntilDone:true
    end if
end run

on doStuff()
    set theFile to ((path to desktop folder as text) & "textB.rtf")
    set fileData to current application's NSData's dataWithContentsOfFile:(POSIX path of theFile)
    set {attrString, attributes} to current application's NSAttributedString's alloc()'s initWithRTF:fileData documentAttributes:(reference)
    if attrString is missing value then error "Unable to read RTF file"
    tell (current application's NSSharingService's sharingServiceNamed:"com.apple.share.Mail.compose") to performWithItems:{attrString}
end doStuff

Thank you, it works like a charm! Perfect!

But, Cocoa is new to me, but I want to learn.... I understand most of what the script does, but do you have a good website with documentation as a starting point?

I also want to change some things, add an attachment, recipient,...
 
Comment

Red Menace

macrumors 6502
May 29, 2011
492
175
Colorado, USA
There are a few resources such as the translation guide from the Mac Automation Scripting Guide, and the Everyday AppleScriptObjC ebook, but there really isn't much AppleScriptObjC specific documentation. It uses the same classes and methods from Apple's documentation in essentially the same way as Objective-C in Xcode (adjusted for AppleScript's syntax, of course), so once you get the hang of translation it isn't too difficult. The main difference is the use of "current application" everywhere (although there are a few shortcuts that can be used), since that is where the various classes and constants are defined.

As an example, my posted script uses a method from the NSSharingService class. Looking at the documentation for that class (in Objective-C), we can see that there are properties for the subject and recipients, and the previously used performWithItems: method/handler that uses a list of items for the share (it uses the item class to determine what to do with it), so the tell statement can be expanded to something like:

AppleScript:
    tell (current application's NSSharingService's sharingServiceNamed:"com.apple.share.Mail.compose")
        set its subject to "This is a test subject"
        set its recipients to {"John Smith <first@someISP.com>", "Jane Doe <second@anotherISP.net>"}
        set attachment to current application's NSURL's fileURLWithPath:(POSIX path of (choose file))
        its performWithItems:{attrString, attachment}
    end tell
 
Comment

Aouttier

macrumors member
Original poster
Mar 3, 2016
40
0
Belgium
I bought the book and installed Xcode, which also contains a large library. Very interesting...

But, I still have 2 questions:
  1. I have multiple accounts on my Mac. How can I define it in the script. I tried Accountname, but that doesn't work (is only for twitter accounts)
  2. In my rtf-file, I want to change some words. Instead of NSAttributedString, I use NSMutableAttributedString. But, I have trouble in finding the correct syntax for replaceCharacters(in:with )
 
Comment

Red Menace

macrumors 6502
May 29, 2011
492
175
Colorado, USA
Xcode is a beast all by itself.

I think the sharing service just uses the default (I haven't really used it), but you can change it from there, or use regular AppleScript to tell Mail to alter the current outgoing message.

Make sure you are viewing the documentation in Objective-C (there is a language choice in the page header) - Swift is a slightly different animal. That method translates to something like:

Code:
attrString's replaceCharactersInRange:{location:5, |length|:20} withString:"some text"
 
Comment

Aouttier

macrumors member
Original poster
Mar 3, 2016
40
0
Belgium
Xcode is a beast all by itself.

I think the sharing service just uses the default (I haven't really used it), but you can change it from there, or use regular AppleScript to tell Mail to alter the current outgoing message.

Make sure you are viewing the documentation in Objective-C (there is a language choice in the page header) - Swift is a slightly different animal. That method translates to something like:

Code:
attrString's replaceCharactersInRange:{location:5, |length|:20} withString:"some text"


Thank you for your help so far, it was very helpful.

The syntax I find on the web for NSattrubutedString is vert different of the syntax above... so it's difficult to find more background

I don't know at which character a word is in the rtf (since I want to use the script multiple times), so I first have to find the location. Do you know such a string. I thought: maybe, I copy it into a NSstring and than I can use the function rangeOfCharacter, which give me the location in the NSattributedstring..... but, I have problem with the correct syntax....
 
Comment

Aouttier

macrumors member
Original poster
Mar 3, 2016
40
0
Belgium
After some trial and error, I found the correct syntax to make a copy into a NSstring, look for the place a certain word and to replace in the original NSMutableAttributedString and paste it into the mail.

For those who are interested:
Code:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

on run -- needs to run on main thread
    if current application's NSThread's isMainThread() as boolean then
        doStuff()
    else
        my performSelectorOnMainThread:"doStuff" withObject:(missing value) waitUntilDone:true
    end if
end run

on doStuff()
    set reFind to "XXXX"
    set reReplace to "YYY"
    --
    set theFile to ((path to desktop folder as text) & "textB.rtf")
    set theattachement to POSIX path of ((path to desktop folder as text) & "File.pdf")
    set fileData to current application's NSData's dataWithContentsOfFile:(POSIX path of theFile)
    set {attrstring, attributes} to current application's NSMutableAttributedString's alloc()'s initWithRTF:fileData documentAttributes:(reference)
    if attrstring is missing value then error "Unable to read RTF file"
    --
    set nsPlainText to attrstring's |string|()
    set theRange to (nsPlainText's rangeOfString:reFind)
    attrstring's replaceCharactersInRange:theRange withString:reReplace
    --
    
    tell (current application's NSSharingService's sharingServiceNamed:"com.apple.share.Mail.compose")
        set its subject to "This is a test subject"
        set its recipients to {"first@someISP.com", "second@anotherISP.net"}
        set bijlage to current application's NSURL's fileURLWithPath:theattachement
        its performWithItems:{attrstring, bijlage}
    end tell

    
end doStuff

Thank you for your help!
 
Comment
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.