Scala: A function to send a text message on Mac/macOS systems (Java, Kotlin, JVM solution)

If you ever need to send a text message on a macOS system when using Scala (or Java, Kotlin, or other JVM languages), I just tested this function, and it seems to work:

import scala.sys.process.*

def sendTextMessage(recipient: String, message: String): Int =
    val appleScript = s"""
        |tell application "Messages"
        |    set targetService to 1st service whose service type = iMessage
        |    set targetBuddy to buddy "$recipient" of targetService
        |    send "$message" to targetBuddy
        |end tell
    """.stripMargin

    Seq("osascript", "-e", appleScript).!

With this function the recipient can be a phone number or email address, and I have only tested the message part as a String so far.

Making the solution a bit more type safe

If you want to make this function a little more type safe, it can also be written like this, using Kit Langton’s Neotype library:

//> using scala "3"
//> using lib "io.github.kitlangton::neotype::0.3.0"

import scala.sys.process.*
import neotype.*

type PhoneNumber = PhoneNumber.Type
object PhoneNumber extends Newtype[String]

type EmailAddress = EmailAddress.Type
object EmailAddress extends Newtype[String]

def sendTextMessage(recipient: PhoneNumber | EmailAddress, message: String): Int =
    val appleScript = s"""
        |tell application "Messages"
        |    set targetService to 1st service whose service type = iMessage
        |    set targetBuddy to buddy "${recipient.toString}" of targetService
        |    send "$message" to targetBuddy
        |end tell
    """.stripMargin

    Seq("osascript", "-e", appleScript).!

@main def SendTextMsg =

    sendTextMessage(
        // EmailAddress("example@acme.com"),
        PhoneNumber("000"),
        "Hi Al, this one uses my phone number."
    )

There may be better ways to handle the unwrapping of the Neotype types — such as calling something like PhoneNumber.unwrap(p) — but for right now, this works okay, albeit with a warning message or two.

You can also create a Message type for the message parameter, but I really just wanted to test union types, so I’ll leave that as an exercise for the reader.