Create Mac Mail msg with Rich Text content that also has cc: address filled in

When I try to use myRtfString (an object with class ConcreteAttributedString) as the body of an email message, it is not accepted:

tell application “Mail”
set theMessage to make new outgoing message with properties {visible:true, content:myRtfString}
– the attempt above to use the NSConcreteAttributedString fails with an error:
(Mail got an error: Can’t get «class ocid» id «data optr00000000206CA30000600000».)

--  but a plain text string works as expected:	
set theMessage to make new outgoing message with properties {visible:true, content:"a plain text string"}

A google search reveals that lots of people have run into this roadblock over the years. I have tried getting the rich text from the pasteboard without success. Has anyone found a solution?

In X-Code, I can load a file and extract myRtfString as an NSAttributedString and then I can use “sharing” to create a rich text email message:

NSSharingService* myMailShareService = [NSSharingService sharingServiceNamed:NSSharingServiceNameComposeEmail];

NSArray* shareItems = @[myRtfString];
[myMailShareService performWithItems:shareItems];

This produces a “message” with the expected rich text content displayed in a new window in Mac Mail. The sharing service also supports setting the to: addresses, the subject, and it supports adding enclosures. BUT the documentation does not mention setting the cc: or bcc: fields, not does it mention how to set a specific sender account. It seems like there should be some way to expose these other message attributes to the NSSharingService interface in X-Code - any ideas how to do this?

After creating a rich text message with myMailShareService, I can get a reference to the new message using AppleScript by searching for its title in the Drafts mailbox. But the found object has class “message”, unlike the the object produced by Applescript above, which has class “outgoing message”. All the attributes of “message”, are read only - unlike an “outgoing message” where they are read/write. So how would I convert a “message” to an “outgoing message” so it can be edited (e.g. fill in the cc: field)?

Thanks in advance for any ideas or solutions.

You can’t pass a pointer («data optr…») to an application like that. But even if you convert it to the RTF as text format, it sadly won’t do what you want.

As for the limitations of NSSharingService, I suspect they are quite deliberate. My impression is that Apple sees Mail automation as a potential vector for malware, so the functionality is deliberately limited. If you want decent email automation, you really need to look at third-party email clients.

Thanks for the quick comment. I wish I could just convert the “message” created by NSSharingService to an “outgoing message” like the ones easily produced by AppleScript. But I don’t know if this is possible. In the mean time, I have resorted to NSSharingService to create the rich text content followed by GUI scripting to fix up the mail fields. There are some differences between OS 10.13 vs 10.14 that I don’t understand when calling procedures in various ways (Accessibility enabled), but the code below seems usable in both. (not sure why the code below is sometimes styled, sometimes in a scroll view ??).

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit" -- needed for used rtf methods and NSSharingService

------------------------- setup for testing ------------------------- 
set aFromAddress to "Joe Smith – joe@gmail.comm" -- with multiple mail accounts, specify the one to use as the sender (exact spelling using m-dash)
set aToAddress to "w@somewhereOrOther.comm"
set uniqueWindowName to "a unique msg subject/window-name"
set testValues to {mailTo:"whyChangeThis?", mailCc:"x@mailCc.Comm", mailBcc:"y@mailBcc.Comm", mailReplyTo:"z@mailReplyTo.Comm", mailSubject:"mailSubject", mailSender:aFromAddress}


(*
-- or construct a unique name for a new mail message window 
property NSDate : a reference to current application's NSDate
set theData to NSDate's timeIntervalSinceReferenceDate
set uniqueWindowName to theData as string
*)

-- Mail must be active with GUI scripting enabled
tell application "System Events"
	if not (exists of application process "Mail") then
		display alert "Mail must be running with accessibility enabled in Secruity settings (to allow GUI scripting)"
		return
	end if
end tell

--              create a message for testing  ----
-- BUT the appleScript translation below only works for OS 10.13.
-- In OS 10.14, create a Rich Text message using the NSSharingService code in objective-c 

-- classes, constants, and enums used for getting the Rich Text
-----   (https://forum.latenightsw.com/t/read-and-write-rtf-files/1200)
property NSData : a reference to current application's NSData
property NSAttributedString : a reference to current application's NSAttributedString
property NSDictionary : a reference to current application's NSDictionary
property NSString : a reference to current application's NSString
property NSRTFTextDocumentType : a reference to current application's NSRTFTextDocumentType

set posixPath to POSIX path of (choose file with prompt "Choose an RTF file" of type {"rtf"})
-- set posixPath to POSIX path of ((path to desktop folder as text) & "test.rtf")
-- read file as RTF data
set theData to NSData's dataWithContentsOfFile:posixPath
-- create attributed string from the data
set {theStyledString, docAttributes} to NSAttributedString's alloc()'s initWithRTF:theData documentAttributes:(reference)
if theStyledString is missing value then error "Could not read RTF file"

-- object-c NSSharingService code to create a Rich Text email - translated to applescript below (but the translation only works in OS 10.13)
(*
	NSSharingService* myMailShareService = [NSSharingService sharingServiceNamed:NSSharingServiceNameComposeEmail];
	myMailShareService.subject = uniqueWindowName; 
	mailShare.recipients = @["denisd@sassafras.com"];
	NSArray* shareItems = @[theStyledString];
	[myMailShareService performWithItems:shareItems];
*)

property NSSharingService : a reference to current application's NSSharingService
set myMailShareService to NSSharingService's sharingServiceNamed:"com.apple.share.Mail.compose"
set subject of myMailShareService to uniqueWindowName
set recipients of myMailShareService to {aToAddress}
set shareItems to {theStyledString}
tell myMailShareService to performWithItems:shareItems
delay 1 -- now mail has a new Rich Text mail msg whose window title is uniqueWindowName


------------------------- end testing setup ------------------------- 

setMailFieldsInMsgWindow(testValues, uniqueWindowName)


on setMailFieldsInMsgWindow(mailFields, windowName)
	
	try
		mailTo of mailFields -- maybe testing the dictionary for the field name before attempting to pass its value makes thread or timing issues more predictable ?? when runing in script debugger??
		my setValueForFieldInWindow(mailTo of mailFields, "To:", windowName) -- mailTo: field can be set by NSSharing, so typically doen't need to be replaced here (so not included in the mailFields dictionary)
	end try
	try
		mailCc of mailFields
		my setValueForFieldInWindow(mailCc of mailFields, "Cc:", windowName)
	end try
	try
		mailBcc of mailFields
		my setValueForFieldInWindow(mailBcc of mailFields, "Bcc:", windowName)
	end try
	try
		mailReplyTo of mailFields
		my setValueForFieldInWindow(mailReplyTo of mailFields, "Reply To:", windowName)
	end try
	try
		mailSubject of mailFields
		my setValueForFieldInWindow(mailSubject of mailFields, "Subject:", windowName)
	end try
	try
		mailSender of mailFields
		my setSenderChoice(mailSender of mailFields, windowName) -- an alert will be posted if there are sender choices displayed but the designated From: address is not available in the pop down menu
	end try
end setMailFieldsInMsgWindow


on setValueForFieldInWindow(theValue, theFieldName, windowName)
	local theFields, theField
	tell application "System Events" to tell process "Mail"
		if system version of (system info) < "10.14" then
			set theFields to get every text field of splitter group 1 of window windowName
		else
			set theFields to get every text field of window windowName
		end if
		
		try
			repeat with a from 1 to count of theFields
				if name of item a of theFields is theFieldName then
					set theField to item a of theFields
					exit repeat
				end if
			end repeat
			set value of theField to theValue
		end try
	end tell
end setValueForFieldInWindow

on setSenderChoice(mailSender, windowName)
	local theSenderPopUp, theSenderMenu, theAccounts, a, theAccount
	tell application "System Events" to tell process "Mail"
		try
			if system version of (system info) < "10.14" then
				set theSenderPopUp to pop up button 1 of splitter group 1 of window windowName
			else
				set theSenderPopUp to pop up button 1 of window windowName
			end if
			
			-- set focused of theSenderPopUp to true
			tell theSenderPopUp
				click
				set theSenderMenu to menu 1 of theSenderPopUp
				set theAccounts to every menu item of theSenderMenu
				
				set a to count of theAccounts
				repeat until a = 0 or title of (item a of theAccounts) = mailSender
					set a to a - 1
				end repeat
				
				if a > 0 then
					set theAccount to menu item a of theSenderMenu
					tell theAccount
						click
					end tell
				else
					display alert "Mail sender account \"" & mailSender & "\" not available."
				end if
			end tell
		end try
	end tell
end setSenderChoice

You should include three backticks (```) on their own line before and after code. I’ve fixed it for you in the post above.