Apple Mail AppleScript 技能
这个技能提供了使用 AppleScript 自动化 Apple Mail 操作的全面指导,包括阅读电子邮件、发送消息和管理邮箱。
核心原则
- 通过账户对象访问邮箱 - 不要尝试直接在账户上访问
inbox - 迭代邮箱以找到正确的一个 - 邮箱名称可能不同(INBOX, Inbox, 等)
- 使用账户名称匹配 - 匹配账户名称而不是电子邮件地址属性
- 优雅地处理错误 - AppleScript 错误可能很隐晦,使用试错法尝试不同的方法
常见查询模式
1. 列出所有邮件账户
始终首先列出账户,以验证账户存在并获取正确的名称:
osascript <<'EOF'
tell application "Mail"
set accountNames to {}
repeat with acc in accounts
set end of accountNames to (name of acc)
end repeat
return accountNames as string
end tell
EOF
示例输出:
MonzoiCloudbrunofdcampos@gmail.commmbcfields@gmail.comcampos.bruno.fd@gmail.com
2. 从账户读取最后 N 封电子邮件
正确的模式 用于从特定账户访问电子邮件:
osascript <<'EOF'
tell application "Mail"
set targetAccount to account "email@example.com"
set allMailboxes to every mailbox of targetAccount
repeat with mbox in allMailboxes
if name of mbox is "INBOX" or name of mbox is "Inbox" then
set inboxMsgs to messages of mbox
set msgCount to count of inboxMsgs
set numToFetch to 5
if msgCount < 5 then set numToFetch to msgCount
set output to ""
repeat with i from 1 to numToFetch
set msg to item i of inboxMsgs
set output to output & "Email #" & i & return
set output to output & "Subject: " & subject of msg & return
set output to output & "From: " & sender of msg & return
set output to output & "Date: " & (date received of msg as string) & return
set output to output & return & "---" & return & return
end repeat
return output
end if
end repeat
return "Inbox not found"
end tell
EOF
从试错中学到的关键课程:
- ❌ 错误:
inbox of targetAccount(不起作用,会导致错误 -1728) - ❌ 错误:
address of acc(address 属性不可靠) - ✅ 正确:
every mailbox of targetAccount然后迭代以找到 “INBOX” 或 “Inbox”
3. 阅读电子邮件内容
获取特定电子邮件的全部正文内容:
osascript <<'EOF'
tell application "Mail"
set targetAccount to account "email@example.com"
set allMailboxes to every mailbox of targetAccount
repeat with mbox in allMailboxes
if name of mbox is "INBOX" or name of mbox is "Inbox" then
set msg to item 1 of messages of mbox
set emailContent to content of msg
return emailContent
end if
end repeat
end tell
EOF
4. 发送电子邮件
创建并发送新电子邮件:
osascript <<'EOF'
tell application "Mail"
set newMessage to make new outgoing message with properties {subject:"Your Subject", content:"Your email body here", visible:true}
tell newMessage
make new to recipient at end of to recipients with properties {address:"recipient@example.com"}
send
end tell
end tell
EOF
选项:
visible:true- 在发送前显示撰写窗口(适合审核)visible:false- 在后台静默发送
5. 回复电子邮件
回复现有电子邮件(保留线程):
osascript <<'EOF'
tell application "Mail"
set targetAccount to account "email@example.com"
set allMailboxes to every mailbox of targetAccount
repeat with mbox in allMailboxes
if name of mbox is "INBOX" or name of mbox is "Inbox" then
-- 根据发件人找到要回复的消息
set foundMessages to (messages of mbox whose sender contains "sender@example.com")
set originalMsg to item 1 of foundMessages
-- 创建回复
set theReply to reply originalMsg
tell theReply
set content to "Your reply message here"
send
end tell
return "Reply sent successfully"
end if
end repeat
end tell
EOF
关键点:
- 使用
reply originalMsg创建一个线程回复(不是make new outgoing message) reply命令自动设置收件人和主题为 “Re:”- 不要使用
with opening window false参数,会导致语法错误 - 在发送前设置回复的内容
回复与新邮件:
- ❌ 错误: 创建新消息给同一收件人(打破线程)
set newMessage to make new outgoing message with properties {subject:"Re: Subject"}
- ✅ 正确: 使用回复命令在原始消息上(保持线程)
set theReply to reply originalMsg
6. 按主题搜索电子邮件
查找匹配特定主题关键词的电子邮件:
osascript <<'EOF'
tell application "Mail"
set targetAccount to account "email@example.com"
set allMailboxes to every mailbox of targetAccount
repeat with mbox in allMailboxes
if name of mbox is "INBOX" or name of mbox is "Inbox" then
set foundMessages to (messages of mbox whose subject contains "keyword")
set output to ""
repeat with msg in foundMessages
set output to output & "Subject: " & subject of msg & return
set output to output & "From: " & sender of msg & return
set output to output & "Date: " & (date received of msg as string) & return
set output to output & "---" & return
end repeat
return output
end if
end repeat
end tell
EOF
7. 按发件人搜索电子邮件
查找来自特定发件人的所有电子邮件:
osascript <<'EOF'
tell application "Mail"
set targetAccount to account "email@example.com"
set allMailboxes to every mailbox of targetAccount
repeat with mbox in allMailboxes
if name of mbox is "INBOX" or name of mbox is "Inbox" then
set foundMessages to (messages of mbox whose sender contains "sender@example.com")
set output to "Found " & (count of foundMessages) & " messages" & return & return
repeat with msg in foundMessages
set output to output & subject of msg & return
end repeat
return output
end if
end repeat
end tell
EOF
8. 获取电子邮件元数据而不加载内容
获取主题、发件人和日期而不加载完整内容(更快):
osascript <<'EOF'
tell application "Mail"
set targetAccount to account "email@example.com"
set allMailboxes to every mailbox of targetAccount
repeat with mbox in allMailboxes
if name of mbox is "INBOX" or name of mbox is "Inbox" then
set recentMsgs to items 1 thru 10 of messages of mbox
set output to ""
repeat with msg in recentMsgs
set output to output & subject of msg & " | " & sender of msg & return
end repeat
return output
end if
end repeat
end tell
EOF
9. 检查未读消息计数
计算收件箱中的未读消息数:
osascript <<'EOF'
tell application "Mail"
set targetAccount to account "email@example.com"
set allMailboxes to every mailbox of targetAccount
repeat with mbox in allMailboxes
if name of mbox is "INBOX" or name of mbox is "Inbox" then
set unreadCount to count of (messages of mbox whose read status is false)
return "Unread messages: " & unreadCount
end if
end repeat
end tell
EOF
10. 将电子邮件移动到邮箱
将消息移动到不同的邮箱:
osascript <<'EOF'
tell application "Mail"
set targetAccount to account "email@example.com"
set allMailboxes to every mailbox of targetAccount
-- 找到源邮箱
repeat with mbox in allMailboxes
if name of mbox is "INBOX" then
set theMessage to item 1 of messages of mbox
-- 找到目标邮箱
repeat with destBox in allMailboxes
if name of destBox is "Archive" then
move theMessage to destBox
return "Message moved to Archive"
end if
end repeat
end if
end repeat
end tell
EOF
11. 按标准删除电子邮件
删除匹配特定标准的电子邮件:
osascript <<'EOF'
tell application "Mail"
set targetAccount to account "email@example.com"
set allMailboxes to every mailbox of targetAccount
repeat with mbox in allMailboxes
if name of mbox is "INBOX" then
set messagesToDelete to (messages of mbox whose subject contains "spam")
repeat with msg in messagesToDelete
delete msg
end repeat
return "Deleted " & (count of messagesToDelete) & " messages"
end if
end repeat
end tell
EOF
常见邮箱名称
不同的电子邮件提供商使用不同的邮箱名称:
Gmail 账户
INBOX- 主收件箱[Gmail]/All Mail- 所有邮件存档[Gmail]/Sent Mail- 发送的消息[Gmail]/Trash- 删除的项目[Gmail]/Drafts- 草稿消息[Gmail]/Spam- 垃圾邮件文件夹
iCloud 账户
Inbox- 主收件箱(注意大小写)Sent Messages- 发送的邮件Trash- 删除的项目Drafts- 草稿消息
其他提供商
- 可能使用
Sent Items,Deleted Items等。 - 总是迭代通过邮箱并检查名称
电子邮件消息属性
您可以访问的常见消息对象属性:
subject of msg -- 电子邮件主题行
sender of msg -- 发件人电子邮件地址
date received of msg -- 电子邮件接收日期
date sent of msg -- 电子邮件发送日期
content of msg -- 完整电子邮件正文(可能很慢)
read status of msg -- 布尔值:如果已读为 true,未读为 false
flagged status of msg -- 布尔值:如果标记/星标为 true
message id of msg -- 唯一消息标识符
to recipients of msg -- 收件人对象列表
cc recipients of msg -- CC 收件人对象列表
all headers of msg -- 原始电子邮件头
message size of msg -- 大小,以字节为单位
错误处理
常见错误和解决方案
错误:“无法获取账户的收件箱”
-- ❌ 错误:尝试直接访问收件箱
tell application "Mail"
set targetAccount to account "email@example.com"
set inboxMsgs to messages of inbox of targetAccount -- 这会失败!
end tell
-- ✅ 正确:迭代邮箱
tell application "Mail"
set targetAccount to account "email@example.com"
set allMailboxes to every mailbox of targetAccount
repeat with mbox in allMailboxes
if name of mbox is "INBOX" or name of mbox is "Inbox" then
set inboxMsgs to messages of mbox
end if
end repeat
end tell
错误:“无法获取账户的地址”
-- ❌ 错误:address 属性不可靠
if address of acc contains "email@example.com" then
-- ✅ 正确:使用 name 属性代替
if name of acc contains "email@example.com" then
错误:“无法获取每个账户的项目 1”
-- ❌ 错误:不要在批量操作中尝试访问属性
repeat with acc in accounts
if address of acc contains "..." then -- 这会失败!
-- ✅ 正确:单独获取属性
repeat with acc in accounts
set accName to name of acc
if accName contains "..." then
错误:消息未找到或邮箱不存在
-- 解决方案:首先检查存在性
set allMailboxes to every mailbox of targetAccount
if (count of allMailboxes) = 0 then
return "No mailboxes found for this account"
end if
最佳实践
-
始终首先列出账户 当调试时:
osascript -e 'tell application "Mail" to name of every account' -
在访问前检查邮箱名称:
set mailboxNames to name of every mailbox of targetAccount -
在 bash 中使用 heredoc 语法 进行多行 AppleScript:
osascript <<'EOF' tell application "Mail" -- 您的脚本在这里 end tell EOF -
处理邮箱名称的大小写敏感性:
if name of mbox is "INBOX" or name of mbox is "Inbox" then -
限制消息检索 以避免减速:
set recentMsgs to items 1 thru 10 of messages of mbox -
在迭代前检查消息计数:
set msgCount to count of messages of mbox if msgCount < numToFetch then set numToFetch to msgCount -
及早使用
return当您找到所需内容时:repeat with mbox in allMailboxes if name of mbox is "INBOX" then -- 处理并返回 return result end if end repeat
性能提示
- 不要不必要地加载内容 - 获取
content of msg很慢 - 限制一次脚本处理的消息数量
- 使用过滤器 (
whose子句)在处理前缩小结果范围 - 如果执行多个操作,缓存邮箱引用
安全和隐私考虑
- 邮件访问需要权限 - macOS 在首次使用时会提示访问权限
- 小心自动化 - 首先使用 visible:true 测试发送脚本
- 尊重用户隐私 - 不要记录敏感电子邮件内容
- 使用特定搜索 - 尽可能避免处理整个邮箱
快速参考命令
# 列出所有账户
osascript -e 'tell application "Mail" to name of every account'
# 获取账户的收件箱消息计数
osascript <<'EOF'
tell application "Mail"
set targetAccount to account "email@example.com"
repeat with mbox in mailboxes of targetAccount
if name of mbox is "INBOX" or name of mbox is "Inbox" then
return count of messages of mbox
end if
end repeat
end tell
EOF
# 获取未读计数
osascript <<'EOF'
tell application "Mail"
set targetAccount to account "email@example.com"
repeat with mbox in mailboxes of targetAccount
if name of mbox is "INBOX" then
return count of (messages of mbox whose read status is false)
end if
end repeat
end tell
EOF
# 列出账户的所有邮箱名称
osascript <<'EOF'
tell application "Mail"
set targetAccount to account "email@example.com"
set mailboxNames to name of every mailbox of targetAccount
return mailboxNames as string
end tell
EOF
何时使用此技能
当您需要:
- 从 Apple Mail 读取电子邮件
- 发送自动化电子邮件
- 回复电子邮件(保持线程上下文)
- 搜索特定电子邮件
- 以编程方式管理邮箱
- 计算未读消息
- 根据标准移动或删除电子邮件
- 提取电子邮件元数据
- 自动化电子邮件工作流
与其他工作流程的集成
当处理电子邮件自动化时:
- 电子邮件通知 - 在特定事件发生时发送警报
- 数据提取 - 解析电子邮件以获取特定信息
- 电子邮件过滤 - 根据规则自动归档或删除电子邮件
- 报告 - 生成电子邮件活动摘要
- 备份 - 导出电子邮件数据以进行归档
从试错中学到的经验(试错)
开发此技能的关键见解:
- 不要直接使用
inbox of account- 总是迭代邮箱 - 账户属性不同 - 使用
name而不是address - 邮箱名称因提供商而异 - 检查 “INBOX” 和 “Inbox”
- 错误 -1728 通常意味着属性不存在 - 尝试不同的属性
- 批量操作
every X可能会失败 - 单独获取属性 - 使用
items 1 thru N进行安全的列表切片,带有边界检查 - 使用
reply命令,而不是新消息 - 要维护线程,请使用reply originalMsg而不是创建新的外发消息 - 不要使用
with opening window参数 -reply命令不支持with opening window false参数,会导致语法错误
记住:AppleScript 错误消息通常很隐晦。当调试时,将脚本简化为最必要的,然后逐渐增加复杂性。