apple-mcp-mail 1.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. apple_mcp_mail-1.0.1/LICENSE +21 -0
  2. apple_mcp_mail-1.0.1/PKG-INFO +157 -0
  3. apple_mcp_mail-1.0.1/README.md +127 -0
  4. apple_mcp_mail-1.0.1/pyproject.toml +61 -0
  5. apple_mcp_mail-1.0.1/setup.cfg +4 -0
  6. apple_mcp_mail-1.0.1/src/apple_mail_mcp/__init__.py +3 -0
  7. apple_mcp_mail-1.0.1/src/apple_mail_mcp/__main__.py +4 -0
  8. apple_mcp_mail-1.0.1/src/apple_mail_mcp/applescripts/compose_draft.applescript +225 -0
  9. apple_mcp_mail-1.0.1/src/apple_mail_mcp/applescripts/delete_message.applescript +54 -0
  10. apple_mcp_mail-1.0.1/src/apple_mail_mcp/applescripts/forward_message.applescript +243 -0
  11. apple_mcp_mail-1.0.1/src/apple_mail_mcp/applescripts/get_message.applescript +151 -0
  12. apple_mcp_mail-1.0.1/src/apple_mail_mcp/applescripts/list_mailboxes.applescript +57 -0
  13. apple_mcp_mail-1.0.1/src/apple_mail_mcp/applescripts/mark_message.applescript +60 -0
  14. apple_mcp_mail-1.0.1/src/apple_mail_mcp/applescripts/move_message.applescript +82 -0
  15. apple_mcp_mail-1.0.1/src/apple_mail_mcp/applescripts/reply_message.applescript +229 -0
  16. apple_mcp_mail-1.0.1/src/apple_mail_mcp/applescripts/search_messages.applescript +136 -0
  17. apple_mcp_mail-1.0.1/src/apple_mail_mcp/applescripts/send_message.applescript +214 -0
  18. apple_mcp_mail-1.0.1/src/apple_mail_mcp/config.py +74 -0
  19. apple_mcp_mail-1.0.1/src/apple_mail_mcp/mail_bridge.py +318 -0
  20. apple_mcp_mail-1.0.1/src/apple_mail_mcp/models.py +276 -0
  21. apple_mcp_mail-1.0.1/src/apple_mail_mcp/permissions.py +56 -0
  22. apple_mcp_mail-1.0.1/src/apple_mail_mcp/tools.py +1043 -0
  23. apple_mcp_mail-1.0.1/src/apple_mcp_mail.egg-info/PKG-INFO +157 -0
  24. apple_mcp_mail-1.0.1/src/apple_mcp_mail.egg-info/SOURCES.txt +30 -0
  25. apple_mcp_mail-1.0.1/src/apple_mcp_mail.egg-info/dependency_links.txt +1 -0
  26. apple_mcp_mail-1.0.1/src/apple_mcp_mail.egg-info/entry_points.txt +3 -0
  27. apple_mcp_mail-1.0.1/src/apple_mcp_mail.egg-info/requires.txt +7 -0
  28. apple_mcp_mail-1.0.1/src/apple_mcp_mail.egg-info/top_level.txt +1 -0
  29. apple_mcp_mail-1.0.1/tests/test_config.py +18 -0
  30. apple_mcp_mail-1.0.1/tests/test_mail_bridge.py +45 -0
  31. apple_mcp_mail-1.0.1/tests/test_permissions.py +16 -0
  32. apple_mcp_mail-1.0.1/tests/test_tools.py +361 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Apple MCP Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,157 @@
1
+ Metadata-Version: 2.4
2
+ Name: apple-mcp-mail
3
+ Version: 1.0.1
4
+ Summary: Local MCP server for Apple Mail on macOS
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://github.com/JonathanRReed/Apple-MCPs
7
+ Project-URL: Repository, https://github.com/JonathanRReed/Apple-MCPs
8
+ Project-URL: Changelog, https://github.com/JonathanRReed/Apple-MCPs/blob/main/CHANGELOG.md
9
+ Project-URL: Issues, https://github.com/JonathanRReed/Apple-MCPs/issues
10
+ Keywords: mcp,model-context-protocol,macos,apple,ai-agent,automation
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Environment :: MacOS X
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: MacOS
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Python: >=3.11
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: apple-mcp-common<2,>=1.0.0
24
+ Requires-Dist: mcp<3,>=2.0.0
25
+ Requires-Dist: pydantic>=2.12.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest<10,>=8; extra == "dev"
28
+ Requires-Dist: ruff<1,>=0.12; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ <!-- mcp-name: io.github.jonathanrreed/apple-mcp-mail -->
32
+
33
+ # Apple Mail MCP
34
+
35
+ MCP server for Apple Mail on macOS.
36
+
37
+ Provides access to mailboxes, message search, reading, and composition. Keep Mail as the system of record while enabling agents to search, read, draft, and send email.
38
+
39
+ ## When to use
40
+
41
+ - Mail-only workflows
42
+ - Tighter permissions than the all-in-one server
43
+ - Draft and send workflows through the native Mail app
44
+
45
+ ## What It Does
46
+
47
+ - List mailboxes
48
+ - Search and read messages
49
+ - Create drafts and send messages
50
+ - Reply, forward, mark read/unread, move, and delete
51
+ - Tool discovery helpers `search_tools` and `get_tool_info` for context-constrained clients
52
+ - Thread helpers: `mail_get_thread`, `mail_reply_latest_in_thread`, `mail_archive_thread`
53
+ - Mailbox resources and reply-oriented prompts
54
+ - Health and permission checks: `mail_health`, `mail_permission_guide`, `mail_recheck_permissions`
55
+
56
+ ## Tools
57
+
58
+ `mail_health`, `mail_permission_guide`, `mail_recheck_permissions`, `mail_list_mailboxes`, `mail_search_messages`, `mail_get_message`, `mail_get_thread`, `mail_compose_draft`, `mail_send_message`, `mail_reply_message`, `mail_forward_message`, `mail_mark_message`, `mail_move_message`, `mail_delete_message`, `mail_reply_latest_in_thread`, `mail_archive_thread`, `mail_list_prompts`, `mail_get_prompt`, plus the discovery helpers `search_tools` and `get_tool_info`.
59
+
60
+ ## Install On This Mac
61
+
62
+ <details>
63
+ <summary>Quick start (uvx, from PyPI)</summary>
64
+
65
+ With [uv](https://docs.astral.sh/uv/getting-started/installation/) installed:
66
+
67
+ ```bash
68
+ uvx apple-mcp-mail
69
+ ```
70
+
71
+ No clone, no venv management.
72
+
73
+ </details>
74
+
75
+ <details>
76
+ <summary>From a clone</summary>
77
+
78
+ ```bash
79
+ git clone https://github.com/JonathanRReed/Apple-MCPs.git
80
+ cd Apple-MCPs
81
+ uv sync --all-packages
82
+ ```
83
+
84
+ This builds one workspace environment with every server's entry point in `.venv/bin` (for example `.venv/bin/apple-mail-mcp`). You can also point an MCP client at `AppleMail-MCP/start.sh`, which prefers `uv run` and falls back to a plain venv bootstrap (Python 3.11+ required).
85
+
86
+ </details>
87
+
88
+ ## Install In AI Agents
89
+
90
+ <details>
91
+ <summary>Generic MCP client config</summary>
92
+
93
+ ```json
94
+ {
95
+ "mcpServers": {
96
+ "apple-mail": {
97
+ "command": "uvx",
98
+ "args": ["apple-mcp-mail"],
99
+ "env": {
100
+ "APPLE_MAIL_MCP_SAFETY_PROFILE": "safe_manage",
101
+ "APPLE_MAIL_MCP_VISIBLE_DRAFTS": "true"
102
+ }
103
+ }
104
+ }
105
+ }
106
+ ```
107
+
108
+ Running from a clone instead? Use `/path/to/Apple-MCPs/AppleMail-MCP/start.sh` as the command with empty `args`.
109
+
110
+ </details>
111
+
112
+ <details>
113
+ <summary>Claude Code example</summary>
114
+
115
+ ```bash
116
+ claude mcp add --transport stdio --scope project apple-mail -- uvx apple-mcp-mail
117
+ ```
118
+
119
+ </details>
120
+
121
+ ## Safety Modes
122
+
123
+ - `safe_readonly`, read and search only
124
+ - `safe_manage`, read plus draft creation
125
+ - `full_access`, full Mail tool surface in this repo
126
+
127
+ ## Transport
128
+
129
+ `stdio` is the default and recommended transport. Set `APPLE_MAIL_MCP_TRANSPORT=streamable-http` (with optional `APPLE_MAIL_MCP_HOST` and `APPLE_MAIL_MCP_PORT`) to serve Streamable HTTP instead.
130
+
131
+ ## macOS Permissions
132
+
133
+ - Automation access to Mail is required
134
+
135
+ ## Launch Checklist
136
+
137
+ - Add `uvx apple-mcp-mail` (or a clone's `AppleMail-MCP/start.sh`) to your MCP client
138
+ - Reload or reconnect the client so the Mail tool surface is loaded into context
139
+ - Call `mail_health` first to confirm the server is reachable
140
+ - If Mail automation is blocked, call `mail_permission_guide`
141
+ - After changing macOS permissions, call `mail_recheck_permissions`
142
+
143
+ ## Prompting Notes
144
+
145
+ - Run Contacts before any send or reply when the user identifies a person rather than an email address.
146
+ - `tools/list` returns the full Mail tool surface. Context-constrained clients can call `search_tools` first, then `get_tool_info` for the exact Mail tool they plan to call.
147
+ - `mail_search_messages` requires a query string. Use a sender, a subject fragment, or `*` as a wildcard.
148
+ - There is no list-all recent-mail endpoint.
149
+ - Use `mail_get_thread` when the user means a conversation, not a single message.
150
+ - Use `mail_reply_latest_in_thread` when the agent should reply to the newest message in the conversation.
151
+ - Use `mail_archive_thread` when the user wants thread-level cleanup and Archive is the intended mailbox.
152
+ - If the user could mean text or email, ask once before choosing Messages or Mail.
153
+ - When Mail must send from a specific identity, pass the exact sender email in `from_account`.
154
+
155
+ ## Related
156
+
157
+ - [Apple-Tools-MCP](../Apple-Tools-MCP/README.md)
@@ -0,0 +1,127 @@
1
+ <!-- mcp-name: io.github.jonathanrreed/apple-mcp-mail -->
2
+
3
+ # Apple Mail MCP
4
+
5
+ MCP server for Apple Mail on macOS.
6
+
7
+ Provides access to mailboxes, message search, reading, and composition. Keep Mail as the system of record while enabling agents to search, read, draft, and send email.
8
+
9
+ ## When to use
10
+
11
+ - Mail-only workflows
12
+ - Tighter permissions than the all-in-one server
13
+ - Draft and send workflows through the native Mail app
14
+
15
+ ## What It Does
16
+
17
+ - List mailboxes
18
+ - Search and read messages
19
+ - Create drafts and send messages
20
+ - Reply, forward, mark read/unread, move, and delete
21
+ - Tool discovery helpers `search_tools` and `get_tool_info` for context-constrained clients
22
+ - Thread helpers: `mail_get_thread`, `mail_reply_latest_in_thread`, `mail_archive_thread`
23
+ - Mailbox resources and reply-oriented prompts
24
+ - Health and permission checks: `mail_health`, `mail_permission_guide`, `mail_recheck_permissions`
25
+
26
+ ## Tools
27
+
28
+ `mail_health`, `mail_permission_guide`, `mail_recheck_permissions`, `mail_list_mailboxes`, `mail_search_messages`, `mail_get_message`, `mail_get_thread`, `mail_compose_draft`, `mail_send_message`, `mail_reply_message`, `mail_forward_message`, `mail_mark_message`, `mail_move_message`, `mail_delete_message`, `mail_reply_latest_in_thread`, `mail_archive_thread`, `mail_list_prompts`, `mail_get_prompt`, plus the discovery helpers `search_tools` and `get_tool_info`.
29
+
30
+ ## Install On This Mac
31
+
32
+ <details>
33
+ <summary>Quick start (uvx, from PyPI)</summary>
34
+
35
+ With [uv](https://docs.astral.sh/uv/getting-started/installation/) installed:
36
+
37
+ ```bash
38
+ uvx apple-mcp-mail
39
+ ```
40
+
41
+ No clone, no venv management.
42
+
43
+ </details>
44
+
45
+ <details>
46
+ <summary>From a clone</summary>
47
+
48
+ ```bash
49
+ git clone https://github.com/JonathanRReed/Apple-MCPs.git
50
+ cd Apple-MCPs
51
+ uv sync --all-packages
52
+ ```
53
+
54
+ This builds one workspace environment with every server's entry point in `.venv/bin` (for example `.venv/bin/apple-mail-mcp`). You can also point an MCP client at `AppleMail-MCP/start.sh`, which prefers `uv run` and falls back to a plain venv bootstrap (Python 3.11+ required).
55
+
56
+ </details>
57
+
58
+ ## Install In AI Agents
59
+
60
+ <details>
61
+ <summary>Generic MCP client config</summary>
62
+
63
+ ```json
64
+ {
65
+ "mcpServers": {
66
+ "apple-mail": {
67
+ "command": "uvx",
68
+ "args": ["apple-mcp-mail"],
69
+ "env": {
70
+ "APPLE_MAIL_MCP_SAFETY_PROFILE": "safe_manage",
71
+ "APPLE_MAIL_MCP_VISIBLE_DRAFTS": "true"
72
+ }
73
+ }
74
+ }
75
+ }
76
+ ```
77
+
78
+ Running from a clone instead? Use `/path/to/Apple-MCPs/AppleMail-MCP/start.sh` as the command with empty `args`.
79
+
80
+ </details>
81
+
82
+ <details>
83
+ <summary>Claude Code example</summary>
84
+
85
+ ```bash
86
+ claude mcp add --transport stdio --scope project apple-mail -- uvx apple-mcp-mail
87
+ ```
88
+
89
+ </details>
90
+
91
+ ## Safety Modes
92
+
93
+ - `safe_readonly`, read and search only
94
+ - `safe_manage`, read plus draft creation
95
+ - `full_access`, full Mail tool surface in this repo
96
+
97
+ ## Transport
98
+
99
+ `stdio` is the default and recommended transport. Set `APPLE_MAIL_MCP_TRANSPORT=streamable-http` (with optional `APPLE_MAIL_MCP_HOST` and `APPLE_MAIL_MCP_PORT`) to serve Streamable HTTP instead.
100
+
101
+ ## macOS Permissions
102
+
103
+ - Automation access to Mail is required
104
+
105
+ ## Launch Checklist
106
+
107
+ - Add `uvx apple-mcp-mail` (or a clone's `AppleMail-MCP/start.sh`) to your MCP client
108
+ - Reload or reconnect the client so the Mail tool surface is loaded into context
109
+ - Call `mail_health` first to confirm the server is reachable
110
+ - If Mail automation is blocked, call `mail_permission_guide`
111
+ - After changing macOS permissions, call `mail_recheck_permissions`
112
+
113
+ ## Prompting Notes
114
+
115
+ - Run Contacts before any send or reply when the user identifies a person rather than an email address.
116
+ - `tools/list` returns the full Mail tool surface. Context-constrained clients can call `search_tools` first, then `get_tool_info` for the exact Mail tool they plan to call.
117
+ - `mail_search_messages` requires a query string. Use a sender, a subject fragment, or `*` as a wildcard.
118
+ - There is no list-all recent-mail endpoint.
119
+ - Use `mail_get_thread` when the user means a conversation, not a single message.
120
+ - Use `mail_reply_latest_in_thread` when the agent should reply to the newest message in the conversation.
121
+ - Use `mail_archive_thread` when the user wants thread-level cleanup and Archive is the intended mailbox.
122
+ - If the user could mean text or email, ask once before choosing Messages or Mail.
123
+ - When Mail must send from a specific identity, pass the exact sender email in `from_account`.
124
+
125
+ ## Related
126
+
127
+ - [Apple-Tools-MCP](../Apple-Tools-MCP/README.md)
@@ -0,0 +1,61 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "apple-mcp-mail"
7
+ version = "1.0.1"
8
+ description = "Local MCP server for Apple Mail on macOS"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.11"
13
+ keywords = ["mcp", "model-context-protocol", "macos", "apple", "ai-agent", "automation"]
14
+ classifiers = [
15
+ "Development Status :: 5 - Production/Stable",
16
+ "Environment :: MacOS X",
17
+ "Intended Audience :: Developers",
18
+ "Operating System :: MacOS",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Programming Language :: Python :: 3.14",
23
+ "Topic :: Software Development :: Libraries :: Python Modules",
24
+ ]
25
+ dependencies = [
26
+ "apple-mcp-common>=1.0.0,<2",
27
+ "mcp>=2.0.0,<3",
28
+ "pydantic>=2.12.0",
29
+ ]
30
+
31
+ [project.urls]
32
+ Homepage = "https://github.com/JonathanRReed/Apple-MCPs"
33
+ Repository = "https://github.com/JonathanRReed/Apple-MCPs"
34
+ Changelog = "https://github.com/JonathanRReed/Apple-MCPs/blob/main/CHANGELOG.md"
35
+ Issues = "https://github.com/JonathanRReed/Apple-MCPs/issues"
36
+
37
+ [project.scripts]
38
+ apple-mail-mcp = "apple_mail_mcp.tools:main"
39
+ apple-mcp-mail = "apple_mail_mcp.tools:main"
40
+
41
+ [project.optional-dependencies]
42
+ dev = [
43
+ "pytest>=8,<10",
44
+ "ruff>=0.12,<1",
45
+ ]
46
+
47
+ [tool.setuptools]
48
+ package-dir = {"" = "src"}
49
+
50
+ [tool.setuptools.package-data]
51
+ apple_mail_mcp = ["applescripts/*.applescript"]
52
+
53
+ [tool.setuptools.packages.find]
54
+ where = ["src"]
55
+
56
+ [tool.pytest.ini_options]
57
+ pythonpath = ["src"]
58
+ testpaths = ["tests"]
59
+
60
+ [tool.uv.sources]
61
+ apple-mcp-common = { workspace = true }
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ __all__ = ["__version__"]
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,4 @@
1
+ from apple_mail_mcp.tools import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1,225 @@
1
+ on splitText(sourceText, separatorValue)
2
+ if sourceText is "" then
3
+ return {}
4
+ end if
5
+ set previousDelimiters to AppleScript's text item delimiters
6
+ set AppleScript's text item delimiters to separatorValue
7
+ set textParts to text items of sourceText
8
+ set AppleScript's text item delimiters to previousDelimiters
9
+ return textParts
10
+ end splitText
11
+
12
+ on replaceText(sourceText, findText, replacementText)
13
+ set previousDelimiters to AppleScript's text item delimiters
14
+ set AppleScript's text item delimiters to findText
15
+ set textParts to text items of sourceText
16
+ set AppleScript's text item delimiters to replacementText
17
+ set outputText to textParts as text
18
+ set AppleScript's text item delimiters to previousDelimiters
19
+ return outputText
20
+ end replaceText
21
+
22
+ on sanitizeText(valueText)
23
+ if valueText is missing value then
24
+ return ""
25
+ end if
26
+ set safeText to valueText as text
27
+ set safeText to my replaceText(safeText, return, "\\n")
28
+ set safeText to my replaceText(safeText, linefeed, "\\n")
29
+ set safeText to my replaceText(safeText, (ASCII character 31), " ")
30
+ set safeText to my replaceText(safeText, (ASCII character 30), " ")
31
+ set safeText to my replaceText(safeText, (ASCII character 29), " ")
32
+ return safeText
33
+ end sanitizeText
34
+
35
+ on normalizeText(valueText)
36
+ if valueText is missing value then
37
+ return ""
38
+ end if
39
+ set normalizedText to do shell script "/bin/echo " & quoted form of (valueText as text) & " | /usr/bin/tr '[:upper:]' '[:lower:]'"
40
+ return normalizedText
41
+ end normalizeText
42
+
43
+ on boolText(flagValue)
44
+ if flagValue then
45
+ return "true"
46
+ end if
47
+ return "false"
48
+ end boolText
49
+
50
+ on resolveAccountBySender(senderRaw)
51
+ if senderRaw is "" then
52
+ return missing value
53
+ end if
54
+ tell application "Mail"
55
+ repeat with theAccount in every account
56
+ try
57
+ if (name of theAccount as text) is senderRaw then
58
+ return theAccount
59
+ end if
60
+ end try
61
+ try
62
+ if (email addresses of theAccount) contains senderRaw then
63
+ return theAccount
64
+ end if
65
+ end try
66
+ end repeat
67
+ end tell
68
+ error "ACCOUNT_NOT_FOUND"
69
+ end resolveAccountBySender
70
+
71
+ on primaryEmailForAccount(theAccount)
72
+ tell application "Mail"
73
+ try
74
+ return item 1 of (email addresses of theAccount) as text
75
+ end try
76
+ end tell
77
+ return ""
78
+ end primaryEmailForAccount
79
+
80
+ on senderMatches(candidateText, senderRaw, senderEmail)
81
+ set normalizedCandidate to my normalizeText(candidateText)
82
+ if senderEmail is not "" then
83
+ set normalizedEmail to my normalizeText(senderEmail)
84
+ if normalizedCandidate contains normalizedEmail then
85
+ return true
86
+ end if
87
+ end if
88
+ if senderRaw is not "" then
89
+ set normalizedSender to my normalizeText(senderRaw)
90
+ if normalizedCandidate contains normalizedSender then
91
+ return true
92
+ end if
93
+ end if
94
+ return false
95
+ end senderMatches
96
+
97
+ on currentSenderMatches(senderRaw, senderEmail)
98
+ tell application "System Events"
99
+ tell process "Mail"
100
+ set frontmost to true
101
+ set composeWindow to front window
102
+ repeat with popupRef in every pop up button of composeWindow
103
+ try
104
+ set currentValue to value of popupRef as text
105
+ if my senderMatches(currentValue, senderRaw, senderEmail) then
106
+ return currentValue
107
+ end if
108
+ end try
109
+ end repeat
110
+ end tell
111
+ end tell
112
+ return ""
113
+ end currentSenderMatches
114
+
115
+ on selectSenderPopup(senderRaw, senderEmail)
116
+ tell application "Mail" to activate
117
+ repeat with attemptIndex from 1 to 5
118
+ delay 0.3
119
+ set currentMatch to my currentSenderMatches(senderRaw, senderEmail)
120
+ if currentMatch is not "" then
121
+ return currentMatch
122
+ end if
123
+ tell application "System Events"
124
+ tell process "Mail"
125
+ set frontmost to true
126
+ set composeWindow to front window
127
+ repeat with popupRef in every pop up button of composeWindow
128
+ click popupRef
129
+ delay 0.25
130
+ set matchingItem to missing value
131
+ try
132
+ repeat with menuItemRef in every menu item of menu 1 of popupRef
133
+ set itemName to name of menuItemRef as text
134
+ if my senderMatches(itemName, senderRaw, senderEmail) then
135
+ set matchingItem to menuItemRef
136
+ exit repeat
137
+ end if
138
+ end repeat
139
+ end try
140
+ if matchingItem is not missing value then
141
+ click matchingItem
142
+ delay 0.4
143
+ set updatedMatch to my currentSenderMatches(senderRaw, senderEmail)
144
+ if updatedMatch is not "" then
145
+ return updatedMatch
146
+ end if
147
+ end if
148
+ key code 53
149
+ delay 0.1
150
+ end repeat
151
+ end tell
152
+ end tell
153
+ end repeat
154
+ error "ACCOUNT_MENU_ITEM_NOT_FOUND"
155
+ end selectSenderPopup
156
+
157
+ on run argv
158
+ set toRaw to item 1 of argv
159
+ set ccRaw to item 2 of argv
160
+ set bccRaw to item 3 of argv
161
+ set subjectText to item 4 of argv
162
+ set bodyText to item 5 of argv
163
+ set attachmentRaw to item 6 of argv
164
+ set visibleText to item 7 of argv
165
+ set senderRaw to item 8 of argv
166
+
167
+ set fieldSeparator to ASCII character 31
168
+ set recordSeparator to ASCII character 30
169
+ set listSeparator to ASCII character 29
170
+ set toList to my splitText(toRaw, listSeparator)
171
+ set ccList to my splitText(ccRaw, listSeparator)
172
+ set bccList to my splitText(bccRaw, listSeparator)
173
+ set attachmentList to my splitText(attachmentRaw, listSeparator)
174
+ set shouldBeVisible to true
175
+ if visibleText is "false" then
176
+ set shouldBeVisible to false
177
+ end if
178
+
179
+ set resolvedAccountLabel to ""
180
+ set senderEmail to ""
181
+
182
+ tell application "Mail"
183
+ set effectiveVisible to shouldBeVisible
184
+ if senderRaw is not "" then
185
+ set effectiveVisible to true
186
+ end if
187
+ set newMessage to make new outgoing message with properties {visible:effectiveVisible, subject:subjectText, content:bodyText}
188
+ if senderRaw is not "" then
189
+ set matchedAccount to my resolveAccountBySender(senderRaw)
190
+ set senderEmail to my primaryEmailForAccount(matchedAccount)
191
+ set sender of newMessage to senderRaw
192
+ delay 0.2
193
+ end if
194
+ tell newMessage
195
+ repeat with addressText in toList
196
+ if (addressText as text) is not "" then
197
+ make new to recipient at end of to recipients with properties {address:addressText as text}
198
+ end if
199
+ end repeat
200
+ repeat with addressText in ccList
201
+ if (addressText as text) is not "" then
202
+ make new cc recipient at end of cc recipients with properties {address:addressText as text}
203
+ end if
204
+ end repeat
205
+ repeat with addressText in bccList
206
+ if (addressText as text) is not "" then
207
+ make new bcc recipient at end of bcc recipients with properties {address:addressText as text}
208
+ end if
209
+ end repeat
210
+ repeat with attachmentPath in attachmentList
211
+ if (attachmentPath as text) is not "" then
212
+ make new attachment with properties {file name:(POSIX file (attachmentPath as text))} at after the last paragraph
213
+ end if
214
+ end repeat
215
+ end tell
216
+ end tell
217
+
218
+ if senderRaw is not "" then
219
+ set resolvedAccountLabel to my sanitizeText(my selectSenderPopup(senderRaw, senderEmail))
220
+ end if
221
+
222
+ tell application "Mail"
223
+ return my sanitizeText((id of newMessage) as text) & fieldSeparator & my boolText(visible of newMessage) & fieldSeparator & resolvedAccountLabel & recordSeparator
224
+ end tell
225
+ end run
@@ -0,0 +1,54 @@
1
+ on boolText(flagValue)
2
+ if flagValue then
3
+ return "true"
4
+ end if
5
+ return "false"
6
+ end boolText
7
+
8
+ on run argv
9
+ set accountName to item 1 of argv
10
+ set mailboxName to item 2 of argv
11
+ set appleId to item 3 of argv
12
+
13
+ set fieldSeparator to ASCII character 31
14
+ set recordSeparator to ASCII character 30
15
+
16
+ tell application "Mail"
17
+ set targetAccount to missing value
18
+ repeat with theAccount in every account
19
+ if (name of theAccount) is accountName then
20
+ set targetAccount to theAccount
21
+ exit repeat
22
+ end if
23
+ end repeat
24
+ if targetAccount is missing value then
25
+ error "ACCOUNT_NOT_FOUND"
26
+ end if
27
+
28
+ set targetMailbox to missing value
29
+ repeat with theMailbox in every mailbox of targetAccount
30
+ if (name of theMailbox) is mailboxName then
31
+ set targetMailbox to theMailbox
32
+ exit repeat
33
+ end if
34
+ end repeat
35
+ if targetMailbox is missing value then
36
+ error "MAILBOX_NOT_FOUND"
37
+ end if
38
+
39
+ set targetMessage to missing value
40
+ repeat with theMessage in messages of targetMailbox
41
+ if ((id of theMessage) as text) is appleId then
42
+ set targetMessage to theMessage
43
+ exit repeat
44
+ end if
45
+ end repeat
46
+ if targetMessage is missing value then
47
+ error "MESSAGE_NOT_FOUND"
48
+ end if
49
+
50
+ delete targetMessage
51
+
52
+ return my boolText(true) & recordSeparator
53
+ end tell
54
+ end run