macOS自带Mail应用:如何检测新邮件到来
思路可行性分析
你的实现思路完全可行:
- 利用
sdef导出Mail应用的脚本定义并生成头文件,是ScriptingBridge开发的标准流程,能让你在Swift中类型安全地调用Mail的AppleScript接口 - ScriptingBridge是Apple官方提供的跨应用脚本交互框架,完全支持对Mail应用的邮件读写操作
现有代码的问题与优化建议
你当前的代码仅能一次性获取收件箱所有邮件,无法实现「检测新邮件」的核心需求,需要补充监听逻辑和新邮件判断机制:
- 添加新邮件监听逻辑
可以通过定时轮询并对比邮件的receivedDate来识别新邮件,也可结合应用激活事件触发检查,示例代码如下:
import Foundation import Mail import AppKit class MailMonitor { let mailApplication: MailApplication var lastCheckedDate: Date = Date() var timer: Timer? init() { mailApplication = SBApplication(bundleIdentifier: "com.apple.mail") as! MailApplication setupTimer() setupWorkspaceObserver() } private func setupTimer() { // 每5分钟轮询一次收件箱 timer = Timer.scheduledTimer(withTimeInterval: 300, repeats: true) { [weak self] _ in self?.checkForNewEmails() } } private func setupWorkspaceObserver() { // 监听Mail应用激活事件,立即检查新邮件 NSWorkspace.shared.notificationCenter.addObserver( self, selector: #selector(checkForNewEmails), name: NSWorkspace.didActivateApplicationNotification, object: nil ) } @objc func checkForNewEmails() { guard let inbox = mailApplication.inboxes?.firstObject as? MailMailbox else { print("无法获取收件箱") return } guard let messages = inbox.messages?().compactMap({ $0 as? MailMessage }) else { print("无法获取邮件列表") return } // 筛选出上次检查之后收到的新邮件 let newMessages = messages.filter { guard let receivedDate = $0.receivedDate else { return false } return receivedDate > lastCheckedDate } if !newMessages.isEmpty { print("发现\(newMessages.count)封新邮件:") for message in newMessages { print("主题:\(message.subject ?? "无主题")") print("发件人:\(message.sender ?? "未知发件人")") print("收到时间:\(message.receivedDate ?? Date())") print("---") } // 更新上次检查时间 lastCheckedDate = Date() } } } // 启动监听 let mailMonitor = MailMonitor() RunLoop.main.run()
- 权限注意事项
- macOS 10.14+需在
Info.plist中添加NSAppleEventsUsageDescription权限说明,否则会被系统拦截 - 若应用为沙盒应用,需开启「Apple Events」权限,并添加对
com.apple.mail的应用访问权限
- 可选替代方案
除了ScriptingBridge,也可直接使用NSAppleScript执行AppleScript代码实现相同功能,简单场景下更灵活,但类型安全性不如ScriptingBridge。
内容的提问来源于stack exchange,提问作者Avi Rok
相关产品推荐
相关产品推荐

