https://github.com/photon-hq/imessage-kit
A type-safe, elegant iMessage SDK for macOS with zero dependencies
https://github.com/photon-hq/imessage-kit
agent ai apple imessage sms typescript
Last synced: 5 months ago
JSON representation
A type-safe, elegant iMessage SDK for macOS with zero dependencies
- Host: GitHub
- URL: https://github.com/photon-hq/imessage-kit
- Owner: photon-hq
- License: mit
- Created: 2025-10-18T06:44:03.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2026-01-13T03:48:10.000Z (5 months ago)
- Last Synced: 2026-01-13T06:50:11.692Z (5 months ago)
- Topics: agent, ai, apple, imessage, sms, typescript
- Language: TypeScript
- Homepage: https://photon.codes
- Size: 4.21 MB
- Stars: 1,038
- Watchers: 33
- Forks: 99
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README

# @photon-ai/imessage-kit
> A type-safe, elegant iMessage SDK for macOS with cross-runtime support
[](https://www.npmjs.com/package/@photon-ai/imessage-kit)
[](https://www.typescriptlang.org/)
[](./LICENSE)
[](https://discord.gg/bZd4CMd2H5)
A full-featured iMessage SDK for **reading**, **sending**, and **automating** iMessage conversations on macOS. Perfect for building AI agents, automation tools, and chat-first applications.
> [!NOTE]
> **✨ Looking for advanced features like threaded replies, tapbacks, message editing, unsending, live typing indicators? Check out [Advanced iMessage Kit](https://github.com/photon-hq/advanced-imessage-kit) and contact us at daniel@photon.codes.**
---
## Features
| Feature | Method | Example |
|---------|--------|---------|
| [Send Messages](#send-messages) | `sdk.send()` | [01-send-text.ts](./examples/01-send-text.ts) |
| [Send Images](#send-images) | `sdk.send()` | [02-send-image.ts](./examples/02-send-image.ts) |
| [Send Files](#send-files) | `sdk.sendFile()` | [03-send-file.ts](./examples/03-send-file.ts) |
| [Send to Groups](#send-to-groups) | `sdk.send()` | [04-send-group.ts](./examples/04-send-group.ts) |
| [Query Messages](#query-messages) | `sdk.getMessages()` | [05-query-messages.ts](./examples/05-query-messages.ts) |
| [List Chats](#list-chats) | `sdk.listChats()` | [06-list-chats.ts](./examples/06-list-chats.ts) |
| [Real-time Watching](#real-time-watching) | `sdk.startWatching()` | [07-watch-messages.ts](./examples/07-watch-messages.ts) |
| [Auto Reply](#auto-reply) | `sdk.message()` | [08-auto-reply.ts](./examples/08-auto-reply.ts) |
| Batch Send | `sdk.sendBatch()` | [09-batch-send.ts](./examples/09-batch-send.ts) |
| Get Sent Message | `sdk.send()` | [10-get-sent-message.ts](./examples/10-get-sent-message.ts) |
| [Plugin System](#plugin-system) | `sdk.use()` | [11-plugin.ts](./examples/11-plugin.ts) |
| [Error Handling](#error-handling) | `SendError` | [12-error-handling.ts](./examples/12-error-handling.ts) |
| Watch Own Messages | `sdk.startWatching()` | [13-watch-own-messages.ts](./examples/13-watch-own-messages.ts) |
| [Scheduled Messages](#scheduled-messages) | `MessageScheduler` | [14-scheduled-messages.ts](./examples/14-scheduled-messages.ts) |
| [Smart Reminders](#smart-reminders) | `Reminders` | [15-smart-reminders.ts](./examples/15-smart-reminders.ts) |
---
## Quick Start
### Installation
```bash
# For Bun (zero dependencies)
bun add @photon-ai/imessage-kit
# For Node.js (requires better-sqlite3)
npm install @photon-ai/imessage-kit better-sqlite3
```
### Basic Usage
```typescript
import { IMessageSDK } from '@photon-ai/imessage-kit'
const sdk = new IMessageSDK()
// Send a message
await sdk.send('+1234567890', 'Hello from iMessage Kit!')
// Clean up
await sdk.close()
```
### Configuration
```typescript
interface IMessageConfig {
debug?: boolean // Enable debug logging
maxConcurrent?: number // Max concurrent sends (default: 5)
scriptTimeout?: number // AppleScript timeout in ms
databasePath?: string // Custom database path
plugins?: Plugin[] // Plugins
watcher?: {
pollInterval?: number // Polling interval (default: 2000)
unreadOnly?: boolean // Only watch unread (default: false)
excludeOwnMessages?: boolean // Exclude own messages (default: true)
}
webhook?: {
url: string
headers?: Record
}
}
```
### Granting Permission
`IMessageKit` requires **Full Disk Access** to read your chat history and perform automation tasks.
1. Open **System Settings → Privacy & Security → Full Disk Access**
2. Click **"+"** and add your IDE or terminal (e.g., Cursor, VS Code, Terminal, Warp)
---
## Messages
> Examples: [01-send-text.ts](./examples/01-send-text.ts) | [02-send-image.ts](./examples/02-send-image.ts) | [03-send-file.ts](./examples/03-send-file.ts) | [05-query-messages.ts](./examples/05-query-messages.ts)
### Send Messages
```typescript
// Send text
await sdk.send('+1234567890', 'Hello World!')
// Send to email
await sdk.send('user@example.com', 'Hello!')
```
### Send Images
```typescript
// Send local images
await sdk.send('+1234567890', {
images: ['image1.jpg', 'image2.png']
})
// Send network images (auto-download)
await sdk.send('+1234567890', {
images: ['https://example.com/image.jpg']
})
// Text with images
await sdk.send('+1234567890', {
text: 'Check this out!',
images: ['photo.jpg']
})
```
### Send Files
```typescript
// Send files (PDF, CSV, VCF, etc.)
await sdk.send('+1234567890', {
files: ['document.pdf', 'data.csv', 'contact.vcf']
})
// Convenience methods
await sdk.sendFile('+1234567890', '/path/to/document.pdf')
await sdk.sendFiles('+1234567890', ['file1.pdf', 'file2.csv'], 'Multiple files')
```
### Query Messages
```typescript
// Get messages with filters
const result = await sdk.getMessages({
sender: '+1234567890',
unreadOnly: true,
limit: 20,
since: new Date('2025-01-01'),
search: 'meeting'
})
// Get unread messages grouped by sender
const unread = await sdk.getUnreadMessages()
console.log(`${unread.total} unread from ${unread.senderCount} senders`)
```
---
## Chats
> Examples: [04-send-group.ts](./examples/04-send-group.ts) | [06-list-chats.ts](./examples/06-list-chats.ts)
### List Chats
```typescript
// Get all chats
const all = await sdk.listChats()
// Filter chats
const groups = await sdk.listChats({
type: 'group',
hasUnread: true,
sortBy: 'recent',
search: 'Project',
limit: 20
})
// Each chat includes
for (const chat of groups) {
console.log({
chatId: chat.chatId,
name: chat.displayName,
isGroup: chat.isGroup,
unread: chat.unreadCount
})
}
```
### Send to Groups
```typescript
// Get group chatId from listChats()
const groups = await sdk.listChats({ type: 'group' })
const chatId = groups[0].chatId // e.g., 'chat45e2b868...'
// Send to group
await sdk.send(chatId, 'Hello group!')
await sdk.send(chatId, {
text: 'Check these files',
files: ['report.pdf']
})
```
---
## Real-time Events
> Examples: [07-watch-messages.ts](./examples/07-watch-messages.ts) | [08-auto-reply.ts](./examples/08-auto-reply.ts) | [13-watch-own-messages.ts](./examples/13-watch-own-messages.ts)
### Real-time Watching
```typescript
await sdk.startWatching({
// All messages
onMessage: (msg) => {
console.log(`New: ${msg.text}`)
},
// DMs only
onDirectMessage: (msg) => {
console.log(`DM from ${msg.sender}`)
},
// Groups only
onGroupMessage: (msg) => {
console.log(`Group: ${msg.chatId}`)
},
onError: (error) => {
console.error(error)
}
})
// Stop watching
sdk.stopWatching()
```
### Auto Reply
```typescript
await sdk.startWatching({
onDirectMessage: async (msg) => {
await sdk.message(msg)
.ifFromOthers()
.matchText(/hello/i)
.replyText('Hi there!')
.execute()
}
})
```
### Message Chain API
```typescript
await sdk.message(msg)
.ifUnread()
.ifNotReaction() // Skip tapback reactions
.ifGroupChat()
.when(m => m.sender.startsWith('+1'))
.matchText(/photo/i)
.replyImage(['photo.jpg'])
.execute()
```
---
## Attachments
> Examples: [02-send-image.ts](./examples/02-send-image.ts) | [03-send-file.ts](./examples/03-send-file.ts)
### Attachment Helpers
```typescript
import {
attachmentExists,
downloadAttachment,
getAttachmentSize,
isImageAttachment,
isVideoAttachment,
isAudioAttachment
} from '@photon-ai/imessage-kit'
const msg = await sdk.getMessages({ hasAttachments: true, limit: 1 })
const attachment = msg.messages[0].attachments[0]
if (await attachmentExists(attachment)) {
const size = await getAttachmentSize(attachment)
if (isImageAttachment(attachment)) {
await downloadAttachment(attachment, '/path/to/save.jpg')
}
}
```
### Supported File Types
- **Documents**: PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX, TXT, RTF
- **Images**: JPG, PNG, GIF, HEIC, WEBP, AVIF
- **Contact Cards**: VCF (vCard)
- **Data Files**: CSV, JSON, XML
- **Archives**: ZIP, RAR, 7Z
- **Media**: MP4, MOV, MP3, M4A
---
## Scheduling
> Examples: [14-scheduled-messages.ts](./examples/14-scheduled-messages.ts) | [15-smart-reminders.ts](./examples/15-smart-reminders.ts)
### Scheduled Messages
```typescript
import { IMessageSDK, MessageScheduler } from '@photon-ai/imessage-kit'
const sdk = new IMessageSDK()
const scheduler = new MessageScheduler(sdk, { debug: true }, {
onSent: (msg, result) => console.log(`✅ Sent: ${msg.id}`),
onError: (msg, error) => console.error(`❌ Failed: ${error.message}`),
onComplete: (msg) => console.log(`🏁 Completed: ${msg.id}`)
})
// One-time message
const id = scheduler.schedule({
to: '+1234567890',
content: 'Reminder!',
sendAt: new Date(Date.now() + 5 * 60 * 1000) // 5 minutes
})
// Recurring daily
scheduler.scheduleRecurring({
to: '+1234567890',
content: 'Good morning! ☀️',
startAt: new Date('2025-01-01T08:00:00'),
interval: 'daily', // 'hourly' | 'daily' | 'weekly' | 'monthly' | number
endAt: new Date('2025-12-31')
})
// Manage
scheduler.reschedule(id, newDate)
scheduler.cancel(id)
scheduler.getPending()
// Persistence
const data = scheduler.export()
scheduler.import(data)
// Cleanup
scheduler.destroy()
```
### Smart Reminders
A human-friendly wrapper for scheduling with natural language:
```typescript
import { IMessageSDK, Reminders } from '@photon-ai/imessage-kit'
const sdk = new IMessageSDK()
const reminders = new Reminders(sdk)
// Relative time
reminders.in('5 minutes', '+1234567890', 'Take a break!')
reminders.in('2 hours', '+1234567890', 'Call the client')
reminders.in('1 day', '+1234567890', 'Follow up')
// Specific time
reminders.at('5pm', '+1234567890', 'End of day review')
reminders.at('tomorrow 9am', '+1234567890', 'Morning standup')
reminders.at('friday 2pm', '+1234567890', 'Weekly sync')
// Exact date
reminders.exact(new Date('2025-12-25T10:00:00'), '+1234567890', 'Merry Christmas!')
// Manage
reminders.list() // List pending
reminders.count() // Count pending
reminders.cancel(id)
reminders.destroy()
```
**Supported formats:**
- Duration: `"5 minutes"`, `"2 hours"`, `"1 day"`, `"30 seconds"`, `"1 week"`
- Time: `"5pm"`, `"5:30pm"`, `"17:30"`
- Day + Time: `"tomorrow 9am"`, `"friday 2pm"`
---
## Plugin System
> Example: [11-plugin.ts](./examples/11-plugin.ts)
```typescript
import { loggerPlugin } from '@photon-ai/imessage-kit'
// Built-in logger
sdk.use(loggerPlugin({
level: 'info',
colored: true
}))
// Custom plugin
sdk.use({
name: 'my-plugin',
onInit: async () => console.log('Initialized'),
onBeforeSend: async (to, content) => {
console.log('Sending to:', to)
return { to, content }
},
onAfterSend: async (result) => {
console.log('Sent:', result)
},
onDestroy: async () => console.log('Destroyed')
})
```
---
## Error Handling
> Example: [12-error-handling.ts](./examples/12-error-handling.ts)
```typescript
import { SendError, DatabaseError, PlatformError } from '@photon-ai/imessage-kit'
try {
await sdk.send('+1234567890', 'Hello')
} catch (error) {
if (error instanceof SendError) {
console.error('Send failed:', error.message)
} else if (error instanceof DatabaseError) {
console.error('Database error:', error.message)
} else if (error instanceof PlatformError) {
console.error('Platform error:', error.message)
}
}
```
---
## Examples
Run any example with Bun:
```bash
bun run examples/.ts
```
### Getting Started
- [01-send-text.ts](./examples/01-send-text.ts) - Basic text message
- [02-send-image.ts](./examples/02-send-image.ts) - Send images
- [03-send-file.ts](./examples/03-send-file.ts) - Send files
### Message Operations
- [05-query-messages.ts](./examples/05-query-messages.ts) - Query messages
- [09-batch-send.ts](./examples/09-batch-send.ts) - Batch sending
- [10-get-sent-message.ts](./examples/10-get-sent-message.ts) - Get sent message
### Chats & Groups
- [04-send-group.ts](./examples/04-send-group.ts) - Send to group
- [06-list-chats.ts](./examples/06-list-chats.ts) - List chats
### Real-time & Automation
- [07-watch-messages.ts](./examples/07-watch-messages.ts) - Watch messages
- [08-auto-reply.ts](./examples/08-auto-reply.ts) - Auto-reply bot
- [13-watch-own-messages.ts](./examples/13-watch-own-messages.ts) - Watch own messages
### Scheduling
- [14-scheduled-messages.ts](./examples/14-scheduled-messages.ts) - Scheduled messages
- [15-smart-reminders.ts](./examples/15-smart-reminders.ts) - Smart reminders
### Advanced
- [11-plugin.ts](./examples/11-plugin.ts) - Custom plugin
- [12-error-handling.ts](./examples/12-error-handling.ts) - Error handling
---
## API Reference
### Core Methods
| Method | Description |
|--------|-------------|
| `getMessages(filter?)` | Query messages with filters |
| `getUnreadMessages()` | Get unread messages grouped by sender |
| `listChats(options?)` | List chats with filtering/sorting |
| `send(to, content)` | Send text, images, and/or files |
| `sendFile(to, path, text?)` | Send a single file |
| `sendFiles(to, paths, text?)` | Send multiple files |
| `sendBatch(messages)` | Send multiple messages concurrently |
| `message(msg)` | Create message processing chain |
| `startWatching(events?)` | Start monitoring new messages |
| `stopWatching()` | Stop monitoring |
| `use(plugin)` | Register plugin |
| `close()` | Close SDK and release resources |
### Types
```typescript
interface Message {
id: string
guid: string
text: string | null
sender: string
senderName: string | null
chatId: string
isGroupChat: boolean
isFromMe: boolean
isRead: boolean
service: 'iMessage' | 'SMS' | 'RCS'
attachments: Attachment[]
date: Date
// Reaction fields
isReaction: boolean
reactionType: 'love' | 'like' | 'dislike' | 'laugh' | 'emphasize' | 'question' | null
isReactionRemoval: boolean
associatedMessageGuid: string | null
}
interface SendResult {
sentAt: Date
message?: Message // Available if watcher is running
}
```
---
## Requirements
- **OS**: macOS only
- **Runtime**: Node.js >= 18.0.0 or Bun >= 1.0.0
- **Permissions**: Full Disk Access
---
## LLMs
Download `llms.txt` for language model context:
- [Download llms.txt](./llms.txt)
### Context7 MCP
- [Context7 Docs](https://context7.com/photon-hq/imessage-kit)
Add [Context7 MCP](https://context7.com/docs/installation) to your IDE, then use:
```
use context7: photon-hq/imessage-kit
```
---
## License
[MIT License](./LICENSE)
---
**Note**: This SDK is for educational and development purposes. Always respect user privacy and follow Apple's terms of service.