Automating Messages (JXA-first with UI/DB fallbacks)
Contents
-
Permissions and scope
-
Default workflow
-
Quick recipe
-
Attachments and UI fallback
-
Data access and forensics
-
Validation Checklist
-
When Not to Use
-
What to load
Permissions and scope
-
Grants needed: Automation + Accessibility; Full Disk Access for any chat.db reads.
-
Keep automation scoped and auditable; avoid unsolicited sends and DB writes.
-
Pairs with automating-mac-apps for common setup (permissions, osascript invocation, UI scripting basics).
Default workflow (happy path)
-
Resolve transport: pick serviceType (iMessage or SMS ) before targeting a buddy.
-
Identify recipient: filter buddies by handle (phone/email). Avoid ambiguous names.
-
Send via app-level send : pass Buddy object to Messages.send() .
-
Verify window context: activate Messages when mixing with UI steps.
-
Fallbacks: if send/attachments fail, use UI scripting; for history, use SQL.
Quick recipe (defensive send)
const Messages = Application('Messages'); Messages.includeStandardAdditions = true;
function safeSend(text, handle, svcType = 'iMessage') {
const svc = Messages.services.whose({ serviceType: svcType })[0];
if (!svc) throw new Error(Service ${svcType} missing);
const buddy = svc.buddies.whose({ handle })[0];
if (!buddy) throw new Error(Buddy ${handle} missing on ${svcType});
Messages.send(text, { to: buddy });
}
-
Wrap with try/catch and log; add small delays when activating UI.
-
For groups, target an existing chat by GUID or fall back to UI scripting; array sends are unreliable.
Attachments and UI fallback
-
Messages lacks a stable JXA attachment API; use clipboard + System Events paste/send.
-
Ensure Accessibility permission, bring app forward, paste file, press Enter.
-
See references/ui-scripting-attachments.md for the full flow and ObjC pasteboard snippet.
Data access and forensics
Reading messages limitation: The AppleScript/JXA API for Messages is effectively write-only. While send() works reliably, reading messages via chat.messages() or similar methods is broken/unsupported in modern macOS. The only reliable way to read message history is via direct SQLite access to ~/Library/Messages/chat.db .
Security consideration: Reading chat.db requires Full Disk Access permission, which grants broad filesystem access beyond just Messages. This is a significant security trade-off - granting Full Disk Access to scripts or applications exposes all user data. Consider whether reading message history is truly necessary before enabling this permission.
-
Use SQL against chat.db for history; JXA chat.messages() is unreliable/non-functional.
-
Requires: System Settings > Privacy & Security > Full Disk Access for your terminal/script.
-
Remember Cocoa epoch conversion (nanoseconds since 2001-01-01); use sqlite3 -json for structured results.
-
See references/database-forensics.md for schema notes, typedstream handling, and export tooling.
Example read query (requires Full Disk Access):
sqlite3 ~/Library/Messages/chat.db "SELECT CASE WHEN m.is_from_me = 1 THEN 'Me' ELSE 'Them' END as sender, m.text, datetime(m.date/1000000000 + 978307200, 'unixepoch', 'localtime') as date FROM message m JOIN handle h ON m.handle_id = h.rowid WHERE h.id LIKE '%PHONE_NUMBER%' ORDER BY m.date DESC LIMIT 10;"
Bots and monitoring
-
Implement polling daemons with launchd now that on-receive handlers are gone.
-
Track rowid , query diffs, dispatch actions, and persist state.
-
See references/monitoring-daemons.md for the polling pattern and plist notes.
Validation Checklist
-
Automation + Accessibility permissions granted
-
Service resolves: Messages.services.whose({ serviceType: 'iMessage' })[0] returns object
-
Buddy lookup works: svc.buddies.whose({ handle })[0] returns target
-
Test send completes without errors
-
Full Disk Access granted if using chat.db reads
When Not to Use
-
For reading message history without Full Disk Access (AppleScript/JXA cannot read messages)
-
For cross-platform messaging (use platform APIs or third-party services)
-
For business SMS automation (use Twilio or similar APIs)
-
When iMessage/SMS features are not available on the target system
-
For bulk messaging (rate limits and security restrictions apply)
-
When security policy prohibits Full Disk Access grants (required for any read operations)
What to load
-
Control plane and send reliability: references/control-plane.md
-
UI scripting + attachments fallback: references/ui-scripting-attachments.md
-
SQL/history access: references/database-forensics.md
-
Polling bots/launchd: references/monitoring-daemons.md