macsync/docs/modules/imail.md

3.3 KiB

iMail (IMailSync)

Purpose

Read Mail.app messages via AppleScript / ScriptingBridge and stream them to the server.

Direction

Read-only in practice (Mac to server). The Sender is implemented but unwired — see known-limitations.

OS surface

Mail.app via ScriptingBridge. The Package.swift:64-66 linker setting pulls in ScriptingBridge.framework. Reader runs synchronously on a background thread (@packages/imail/Sources/IMailSync/SyncManager.swift:90-93). Requires Automation > Mail permission.

Files

  • Reader.swiftReader.shared; fetchMessages(since:) traverses Mail.app accounts, mailboxes, and messages. Applies a ±1-minute watermark tolerance (documented at SyncManager.swift:40-43).
  • MIMEParser.swift — minimal MIME header decoder used by the Reader.
  • APIClient.swift:
    • syncMail(_:) -> POST /client/imail/sync (@packages/imail/Sources/IMailSync/APIClient.swift:86-88)
    • getStats() -> GET /client/imail/stats (line 102-103)
  • Sender.swiftSender.send(_:) drives Mail.app via ScriptingBridge.
  • SendQueueAdapter.swiftIMailSendTransport + MailSender + dispatch closure. Used by the SyncManager's SendQueueClient to drain /client/imail/send-queue/pending.
  • APIClient.swiftgetPendingSends() / reportSendResult(...) added alongside the existing read endpoints.
  • SyncManager.swift — reads off-main, batches 50; owns a lazy SendQueueClient<IMailSendTransport> started via didStartSync() and stopped via willStopSync().

Timing

  • Read interval: 300s (@packages/imail/Sources/IMailSync/SyncManager.swift:61).
  • Outbound SendQueueClient: 60s.
  • Batch size: 50.

Server surface

  • Entity tables: existing mail-ingest tables live under features/imail/; outbound table is icloud.mail_send_queue (src/server/src/entities/mailSendItem/schema.ts), built on the shared sendQueueTableSql factory.
  • Client routes (src/server/src/surfaces/client/imail.ts):
    • GET /client/imail/stats
    • POST /client/imail/sync
    • GET /client/imail/send-queue/pending
    • POST /client/imail/send-queue/:id/result
  • Web routes (src/server/src/surfaces/my/mail.ts):
    • GET /my/mail/conversations
    • GET /my/mail/conversations/:id/messages
    • GET /my/mail/last-sync
    • POST /my/mail/send — enqueues a send_mail action
  • Admin route (src/server/src/surfaces/admin/mail-send-queue.ts):
    • POST /admin/mail-send-queue/enqueue

Web surface

  • Tab: /mail (web/src/App.tsx:59).
  • API helpers: web/src/api/mail.ts.

Known limitations

  • AppleScript / ScriptingBridge fragility. The reader runs in a detached Task but a hung Mail.app blocks until macOS times the Apple event out. The send path inherits the same constraint.
  • No folder browser in /my/mail; only conversations and messages by ID.
  • No CC/BCC UI in the web Compose form yet (the server payload schema and Sender both accept them; only the web form is missing them).

Tests (@packages/imail/Tests/IMailSyncTests/)

  • MIMEParserTests.swift — header decoding (hermetic).
  • SenderTests.swiftMailSender dispatch with a FakeApplier: success path, unknown-action failure, error propagation.

Not covered by tests: Mail.app reading, ScriptingBridge bindings, live send.