6

I would like use Javascript for Automation in OS X Yosemite to create a new email message in Mail.app and attach a file to the email. This is my code:

Mail = Application('com.apple.Mail')
message = Mail.OutgoingMessage().make()
message.visible = true
message.toRecipients.push(Mail.Recipient({ address: "abc@example.com" }))
message.subject = "Test subject"
message.content = "Lorem ipsum dolor sit"

It works fine until this point. I see a new message window with the recipient, subject, and body text correctly filled in. But I can’t figure out how to add a file attachment to the message. The scripting dictionary for Mail.app indicates that the contents property (an instance of RichText) can contain attachments, but I don’t know how to add one.

I tried this but I get an error:

// This doesn't work.
attachment = Mail.Attachment({ fileName: "/Users/myname/Desktop/test.pdf" })
message.content.attachments = [ attachment ]
// Error: Can't convert types.

I found several examples on the web how to do this in AppleScript, for example this one:

tell application "Mail"
    ...
    set theAttachmentFile to "Macintosh HD:Users:moligaloo:Downloads:attachment.pdf"
    set msg to make new outgoing message with properties {subject: theSubject, content: theContent, visible:true}

    tell msg to make new attachment with properties {file name:theAttachmentFile as alias}
end tell

But I can’t figure out how to convert this to Javascript.

Ole Begemann
  • 135,006
  • 31
  • 278
  • 256

2 Answers2

7

I figured out a way to do this through trial and error, you need to use message.attachments.push(attachment) instead of attachments = [...]

Mail = Application('com.apple.Mail')
message = Mail.OutgoingMessage().make()
message.visible = true
message.toRecipients.push(Mail.Recipient({ address: "foo.bar@example.com" }))
message.subject = "Testing JXA"
message.content = "Foo bar baz"

attachment = Mail.Attachment({ fileName: "/Users/myname/Desktop/test.pdf" })
message.attachments.push(attachment)
tlehman
  • 5,125
  • 2
  • 33
  • 51
  • 1
    Yup, it's one of several idiotic obfuscations in JXA. The correct syntax _should_ be `Mail.make({new:k.outgoingMessage, at:message.attachments, withProperties:{visible:true,subject:"Test",content:"Foo"}})`, because that's how Apple events _actually_ work; i.e. RPC + simple relational queries. But the AS team insists on lying to users of languages such as JavaScript and Objective-C, so you have to wade through this faux-OOP crap that pretends (badly) that you're manipulating a local `Array` object instead of describing a one-to-many relationship in the remote process's object graph. #HeadDesk – foo Jan 03 '15 at 18:37
  • Yeah, it should just match the underlying concepts, they are not hard to understand. – tlehman Jan 04 '15 at 18:28
  • 1
    Yup. I've been banging my head against a wall trying to tell the AppleScript/JXA developers this. Apple event IPC is actually very easy and logical to understand once you realize it's __not__ OOP. What's really frustrating is that if JXA did match the underlying concepts, it'd be trivially easy to provide users with an automatic translation tool (c.f. [ASTranslate](http://appscript.sourceforge.net/tools.html)) that converts AppleScript commands to the equivalent JavaScript syntax, at which point 90% of "How do I convert this AppleScript to " questions effectively answer themselves. – foo Jan 05 '15 at 15:24
  • 1
    BTW, I sent the AS/JXA team a a nearly complete [JavaScript OSA](https://sourceforge.net/projects/appscript/files) reference implementation. Its Apple event support derives from the old appscript bridge which, unlike JXA, went through many thousands of hours of relentless tyre-kicking and real-world use with hundreds of scriptable apps by hundreds of personal and professional users, not least myself. Buggy and unpolished, but worth a look if you're curious as to how JXA could/should work. Maybe if enough JS users get mad at JXA they can have a mass pile on to force Apple to redo it right. – foo Jan 05 '15 at 15:34
  • 1
    @foo What is `k` in your code sample (first commend above) and why `at:message.attachements`, why `at`? This makes it sound as if a new mail shall be created as an attachment. – Mecki Oct 23 '17 at 15:56
7

Building on the answer above by @tlehman, I found that his solution worked very well, except for one thing: The attachments were NOT successful. No errors, no messages, the attachment just was not made to the message. The solution is to use the Path() method.

Here is his solution + the Path() method, which is needed if there are any spaces in the path:

Mail = Application('com.apple.Mail')
message = Mail.OutgoingMessage().make()
message.visible = true
message.toRecipients.push(Mail.Recipient({ address: "foo.bar@example.com" }))
message.subject = "Testing JXA"
message.content = "Foo bar baz"

attachment = Mail.Attachment({ fileName: Path("/Users/myname/Desktop/if the file has spaces in it test.pdf") })
message.attachments.push(attachment)
JMichaelTX
  • 1,659
  • 14
  • 19