universal-mcp-applications 0.1.1__py3-none-any.whl

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 (268) hide show
  1. universal_mcp/applications/ahrefs/README.md +51 -0
  2. universal_mcp/applications/ahrefs/__init__.py +1 -0
  3. universal_mcp/applications/ahrefs/app.py +2291 -0
  4. universal_mcp/applications/airtable/README.md +22 -0
  5. universal_mcp/applications/airtable/__init__.py +1 -0
  6. universal_mcp/applications/airtable/app.py +479 -0
  7. universal_mcp/applications/apollo/README.md +44 -0
  8. universal_mcp/applications/apollo/__init__.py +1 -0
  9. universal_mcp/applications/apollo/app.py +1847 -0
  10. universal_mcp/applications/asana/README.md +199 -0
  11. universal_mcp/applications/asana/__init__.py +1 -0
  12. universal_mcp/applications/asana/app.py +9509 -0
  13. universal_mcp/applications/aws-s3/README.md +0 -0
  14. universal_mcp/applications/aws-s3/__init__.py +1 -0
  15. universal_mcp/applications/aws-s3/app.py +552 -0
  16. universal_mcp/applications/bill/README.md +0 -0
  17. universal_mcp/applications/bill/__init__.py +1 -0
  18. universal_mcp/applications/bill/app.py +8705 -0
  19. universal_mcp/applications/box/README.md +307 -0
  20. universal_mcp/applications/box/__init__.py +1 -0
  21. universal_mcp/applications/box/app.py +15987 -0
  22. universal_mcp/applications/braze/README.md +106 -0
  23. universal_mcp/applications/braze/__init__.py +1 -0
  24. universal_mcp/applications/braze/app.py +4754 -0
  25. universal_mcp/applications/cal-com-v2/README.md +150 -0
  26. universal_mcp/applications/cal-com-v2/__init__.py +1 -0
  27. universal_mcp/applications/cal-com-v2/app.py +5541 -0
  28. universal_mcp/applications/calendly/README.md +53 -0
  29. universal_mcp/applications/calendly/__init__.py +1 -0
  30. universal_mcp/applications/calendly/app.py +1436 -0
  31. universal_mcp/applications/canva/README.md +43 -0
  32. universal_mcp/applications/canva/__init__.py +1 -0
  33. universal_mcp/applications/canva/app.py +941 -0
  34. universal_mcp/applications/clickup/README.md +135 -0
  35. universal_mcp/applications/clickup/__init__.py +1 -0
  36. universal_mcp/applications/clickup/app.py +5009 -0
  37. universal_mcp/applications/coda/README.md +108 -0
  38. universal_mcp/applications/coda/__init__.py +1 -0
  39. universal_mcp/applications/coda/app.py +3671 -0
  40. universal_mcp/applications/confluence/README.md +198 -0
  41. universal_mcp/applications/confluence/__init__.py +1 -0
  42. universal_mcp/applications/confluence/app.py +6273 -0
  43. universal_mcp/applications/contentful/README.md +17 -0
  44. universal_mcp/applications/contentful/__init__.py +1 -0
  45. universal_mcp/applications/contentful/app.py +364 -0
  46. universal_mcp/applications/crustdata/README.md +25 -0
  47. universal_mcp/applications/crustdata/__init__.py +1 -0
  48. universal_mcp/applications/crustdata/app.py +586 -0
  49. universal_mcp/applications/dialpad/README.md +202 -0
  50. universal_mcp/applications/dialpad/__init__.py +1 -0
  51. universal_mcp/applications/dialpad/app.py +5949 -0
  52. universal_mcp/applications/digitalocean/README.md +463 -0
  53. universal_mcp/applications/digitalocean/__init__.py +1 -0
  54. universal_mcp/applications/digitalocean/app.py +20835 -0
  55. universal_mcp/applications/domain-checker/README.md +13 -0
  56. universal_mcp/applications/domain-checker/__init__.py +1 -0
  57. universal_mcp/applications/domain-checker/app.py +265 -0
  58. universal_mcp/applications/e2b/README.md +12 -0
  59. universal_mcp/applications/e2b/__init__.py +1 -0
  60. universal_mcp/applications/e2b/app.py +187 -0
  61. universal_mcp/applications/elevenlabs/README.md +88 -0
  62. universal_mcp/applications/elevenlabs/__init__.py +1 -0
  63. universal_mcp/applications/elevenlabs/app.py +3235 -0
  64. universal_mcp/applications/exa/README.md +15 -0
  65. universal_mcp/applications/exa/__init__.py +1 -0
  66. universal_mcp/applications/exa/app.py +221 -0
  67. universal_mcp/applications/falai/README.md +17 -0
  68. universal_mcp/applications/falai/__init__.py +1 -0
  69. universal_mcp/applications/falai/app.py +331 -0
  70. universal_mcp/applications/figma/README.md +49 -0
  71. universal_mcp/applications/figma/__init__.py +1 -0
  72. universal_mcp/applications/figma/app.py +1090 -0
  73. universal_mcp/applications/firecrawl/README.md +20 -0
  74. universal_mcp/applications/firecrawl/__init__.py +1 -0
  75. universal_mcp/applications/firecrawl/app.py +514 -0
  76. universal_mcp/applications/fireflies/README.md +25 -0
  77. universal_mcp/applications/fireflies/__init__.py +1 -0
  78. universal_mcp/applications/fireflies/app.py +506 -0
  79. universal_mcp/applications/fpl/README.md +23 -0
  80. universal_mcp/applications/fpl/__init__.py +1 -0
  81. universal_mcp/applications/fpl/app.py +1327 -0
  82. universal_mcp/applications/fpl/utils/api.py +142 -0
  83. universal_mcp/applications/fpl/utils/fixtures.py +629 -0
  84. universal_mcp/applications/fpl/utils/helper.py +982 -0
  85. universal_mcp/applications/fpl/utils/league_utils.py +546 -0
  86. universal_mcp/applications/fpl/utils/position_utils.py +68 -0
  87. universal_mcp/applications/ghost-content/README.md +25 -0
  88. universal_mcp/applications/ghost-content/__init__.py +1 -0
  89. universal_mcp/applications/ghost-content/app.py +654 -0
  90. universal_mcp/applications/github/README.md +1049 -0
  91. universal_mcp/applications/github/__init__.py +1 -0
  92. universal_mcp/applications/github/app.py +50600 -0
  93. universal_mcp/applications/gong/README.md +63 -0
  94. universal_mcp/applications/gong/__init__.py +1 -0
  95. universal_mcp/applications/gong/app.py +2297 -0
  96. universal_mcp/applications/google-ads/README.md +0 -0
  97. universal_mcp/applications/google-ads/__init__.py +1 -0
  98. universal_mcp/applications/google-ads/app.py +23 -0
  99. universal_mcp/applications/google-calendar/README.md +21 -0
  100. universal_mcp/applications/google-calendar/__init__.py +1 -0
  101. universal_mcp/applications/google-calendar/app.py +574 -0
  102. universal_mcp/applications/google-docs/README.md +25 -0
  103. universal_mcp/applications/google-docs/__init__.py +1 -0
  104. universal_mcp/applications/google-docs/app.py +760 -0
  105. universal_mcp/applications/google-drive/README.md +68 -0
  106. universal_mcp/applications/google-drive/__init__.py +1 -0
  107. universal_mcp/applications/google-drive/app.py +4936 -0
  108. universal_mcp/applications/google-gemini/README.md +25 -0
  109. universal_mcp/applications/google-gemini/__init__.py +1 -0
  110. universal_mcp/applications/google-gemini/app.py +663 -0
  111. universal_mcp/applications/google-mail/README.md +31 -0
  112. universal_mcp/applications/google-mail/__init__.py +1 -0
  113. universal_mcp/applications/google-mail/app.py +1354 -0
  114. universal_mcp/applications/google-searchconsole/README.md +21 -0
  115. universal_mcp/applications/google-searchconsole/__init__.py +1 -0
  116. universal_mcp/applications/google-searchconsole/app.py +320 -0
  117. universal_mcp/applications/google-sheet/README.md +36 -0
  118. universal_mcp/applications/google-sheet/__init__.py +1 -0
  119. universal_mcp/applications/google-sheet/app.py +1941 -0
  120. universal_mcp/applications/hashnode/README.md +20 -0
  121. universal_mcp/applications/hashnode/__init__.py +1 -0
  122. universal_mcp/applications/hashnode/app.py +455 -0
  123. universal_mcp/applications/heygen/README.md +44 -0
  124. universal_mcp/applications/heygen/__init__.py +1 -0
  125. universal_mcp/applications/heygen/app.py +961 -0
  126. universal_mcp/applications/http-tools/README.md +16 -0
  127. universal_mcp/applications/http-tools/__init__.py +1 -0
  128. universal_mcp/applications/http-tools/app.py +153 -0
  129. universal_mcp/applications/hubspot/README.md +239 -0
  130. universal_mcp/applications/hubspot/__init__.py +1 -0
  131. universal_mcp/applications/hubspot/app.py +416 -0
  132. universal_mcp/applications/jira/README.md +600 -0
  133. universal_mcp/applications/jira/__init__.py +1 -0
  134. universal_mcp/applications/jira/app.py +28804 -0
  135. universal_mcp/applications/klaviyo/README.md +313 -0
  136. universal_mcp/applications/klaviyo/__init__.py +1 -0
  137. universal_mcp/applications/klaviyo/app.py +11236 -0
  138. universal_mcp/applications/linkedin/README.md +15 -0
  139. universal_mcp/applications/linkedin/__init__.py +1 -0
  140. universal_mcp/applications/linkedin/app.py +243 -0
  141. universal_mcp/applications/mailchimp/README.md +281 -0
  142. universal_mcp/applications/mailchimp/__init__.py +1 -0
  143. universal_mcp/applications/mailchimp/app.py +10937 -0
  144. universal_mcp/applications/markitdown/README.md +12 -0
  145. universal_mcp/applications/markitdown/__init__.py +1 -0
  146. universal_mcp/applications/markitdown/app.py +63 -0
  147. universal_mcp/applications/miro/README.md +151 -0
  148. universal_mcp/applications/miro/__init__.py +1 -0
  149. universal_mcp/applications/miro/app.py +5429 -0
  150. universal_mcp/applications/ms-teams/README.md +42 -0
  151. universal_mcp/applications/ms-teams/__init__.py +1 -0
  152. universal_mcp/applications/ms-teams/app.py +1823 -0
  153. universal_mcp/applications/neon/README.md +74 -0
  154. universal_mcp/applications/neon/__init__.py +1 -0
  155. universal_mcp/applications/neon/app.py +2018 -0
  156. universal_mcp/applications/notion/README.md +30 -0
  157. universal_mcp/applications/notion/__init__.py +1 -0
  158. universal_mcp/applications/notion/app.py +527 -0
  159. universal_mcp/applications/openai/README.md +22 -0
  160. universal_mcp/applications/openai/__init__.py +1 -0
  161. universal_mcp/applications/openai/app.py +759 -0
  162. universal_mcp/applications/outlook/README.md +20 -0
  163. universal_mcp/applications/outlook/__init__.py +1 -0
  164. universal_mcp/applications/outlook/app.py +444 -0
  165. universal_mcp/applications/perplexity/README.md +12 -0
  166. universal_mcp/applications/perplexity/__init__.py +1 -0
  167. universal_mcp/applications/perplexity/app.py +65 -0
  168. universal_mcp/applications/pipedrive/README.md +284 -0
  169. universal_mcp/applications/pipedrive/__init__.py +1 -0
  170. universal_mcp/applications/pipedrive/app.py +12924 -0
  171. universal_mcp/applications/posthog/README.md +132 -0
  172. universal_mcp/applications/posthog/__init__.py +1 -0
  173. universal_mcp/applications/posthog/app.py +7125 -0
  174. universal_mcp/applications/reddit/README.md +135 -0
  175. universal_mcp/applications/reddit/__init__.py +1 -0
  176. universal_mcp/applications/reddit/app.py +4652 -0
  177. universal_mcp/applications/replicate/README.md +18 -0
  178. universal_mcp/applications/replicate/__init__.py +1 -0
  179. universal_mcp/applications/replicate/app.py +495 -0
  180. universal_mcp/applications/resend/README.md +40 -0
  181. universal_mcp/applications/resend/__init__.py +1 -0
  182. universal_mcp/applications/resend/app.py +881 -0
  183. universal_mcp/applications/retell/README.md +21 -0
  184. universal_mcp/applications/retell/__init__.py +1 -0
  185. universal_mcp/applications/retell/app.py +333 -0
  186. universal_mcp/applications/rocketlane/README.md +70 -0
  187. universal_mcp/applications/rocketlane/__init__.py +1 -0
  188. universal_mcp/applications/rocketlane/app.py +4346 -0
  189. universal_mcp/applications/semanticscholar/README.md +25 -0
  190. universal_mcp/applications/semanticscholar/__init__.py +1 -0
  191. universal_mcp/applications/semanticscholar/app.py +482 -0
  192. universal_mcp/applications/semrush/README.md +44 -0
  193. universal_mcp/applications/semrush/__init__.py +1 -0
  194. universal_mcp/applications/semrush/app.py +2081 -0
  195. universal_mcp/applications/sendgrid/README.md +362 -0
  196. universal_mcp/applications/sendgrid/__init__.py +1 -0
  197. universal_mcp/applications/sendgrid/app.py +9752 -0
  198. universal_mcp/applications/sentry/README.md +186 -0
  199. universal_mcp/applications/sentry/__init__.py +1 -0
  200. universal_mcp/applications/sentry/app.py +7471 -0
  201. universal_mcp/applications/serpapi/README.md +14 -0
  202. universal_mcp/applications/serpapi/__init__.py +1 -0
  203. universal_mcp/applications/serpapi/app.py +293 -0
  204. universal_mcp/applications/sharepoint/README.md +0 -0
  205. universal_mcp/applications/sharepoint/__init__.py +1 -0
  206. universal_mcp/applications/sharepoint/app.py +215 -0
  207. universal_mcp/applications/shopify/README.md +321 -0
  208. universal_mcp/applications/shopify/__init__.py +1 -0
  209. universal_mcp/applications/shopify/app.py +15392 -0
  210. universal_mcp/applications/shortcut/README.md +128 -0
  211. universal_mcp/applications/shortcut/__init__.py +1 -0
  212. universal_mcp/applications/shortcut/app.py +4478 -0
  213. universal_mcp/applications/slack/README.md +0 -0
  214. universal_mcp/applications/slack/__init__.py +1 -0
  215. universal_mcp/applications/slack/app.py +570 -0
  216. universal_mcp/applications/spotify/README.md +91 -0
  217. universal_mcp/applications/spotify/__init__.py +1 -0
  218. universal_mcp/applications/spotify/app.py +2526 -0
  219. universal_mcp/applications/supabase/README.md +87 -0
  220. universal_mcp/applications/supabase/__init__.py +1 -0
  221. universal_mcp/applications/supabase/app.py +2970 -0
  222. universal_mcp/applications/tavily/README.md +12 -0
  223. universal_mcp/applications/tavily/__init__.py +1 -0
  224. universal_mcp/applications/tavily/app.py +51 -0
  225. universal_mcp/applications/trello/README.md +266 -0
  226. universal_mcp/applications/trello/__init__.py +1 -0
  227. universal_mcp/applications/trello/app.py +10875 -0
  228. universal_mcp/applications/twillo/README.md +0 -0
  229. universal_mcp/applications/twillo/__init__.py +1 -0
  230. universal_mcp/applications/twillo/app.py +269 -0
  231. universal_mcp/applications/twitter/README.md +100 -0
  232. universal_mcp/applications/twitter/__init__.py +1 -0
  233. universal_mcp/applications/twitter/api_segments/__init__.py +0 -0
  234. universal_mcp/applications/twitter/api_segments/api_segment_base.py +51 -0
  235. universal_mcp/applications/twitter/api_segments/compliance_api.py +122 -0
  236. universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +255 -0
  237. universal_mcp/applications/twitter/api_segments/dm_events_api.py +140 -0
  238. universal_mcp/applications/twitter/api_segments/likes_api.py +159 -0
  239. universal_mcp/applications/twitter/api_segments/lists_api.py +395 -0
  240. universal_mcp/applications/twitter/api_segments/openapi_json_api.py +34 -0
  241. universal_mcp/applications/twitter/api_segments/spaces_api.py +309 -0
  242. universal_mcp/applications/twitter/api_segments/trends_api.py +40 -0
  243. universal_mcp/applications/twitter/api_segments/tweets_api.py +1403 -0
  244. universal_mcp/applications/twitter/api_segments/usage_api.py +40 -0
  245. universal_mcp/applications/twitter/api_segments/users_api.py +1498 -0
  246. universal_mcp/applications/twitter/app.py +46 -0
  247. universal_mcp/applications/unipile/README.md +28 -0
  248. universal_mcp/applications/unipile/__init__.py +1 -0
  249. universal_mcp/applications/unipile/app.py +829 -0
  250. universal_mcp/applications/whatsapp/README.md +23 -0
  251. universal_mcp/applications/whatsapp/__init__.py +1 -0
  252. universal_mcp/applications/whatsapp/app.py +595 -0
  253. universal_mcp/applications/whatsapp-business/README.md +34 -0
  254. universal_mcp/applications/whatsapp-business/__init__.py +1 -0
  255. universal_mcp/applications/whatsapp-business/app.py +1065 -0
  256. universal_mcp/applications/wrike/README.md +46 -0
  257. universal_mcp/applications/wrike/__init__.py +1 -0
  258. universal_mcp/applications/wrike/app.py +1583 -0
  259. universal_mcp/applications/youtube/README.md +57 -0
  260. universal_mcp/applications/youtube/__init__.py +1 -0
  261. universal_mcp/applications/youtube/app.py +1696 -0
  262. universal_mcp/applications/zenquotes/README.md +12 -0
  263. universal_mcp/applications/zenquotes/__init__.py +1 -0
  264. universal_mcp/applications/zenquotes/app.py +31 -0
  265. universal_mcp_applications-0.1.1.dist-info/METADATA +172 -0
  266. universal_mcp_applications-0.1.1.dist-info/RECORD +268 -0
  267. universal_mcp_applications-0.1.1.dist-info/WHEEL +4 -0
  268. universal_mcp_applications-0.1.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,1354 @@
1
+ import base64
2
+ import concurrent.futures
3
+ from email.message import EmailMessage
4
+ from typing import Any
5
+
6
+ from loguru import logger
7
+ from universal_mcp.applications.application import APIApplication
8
+ from universal_mcp.integrations import Integration
9
+
10
+
11
+ class GoogleMailApp(APIApplication):
12
+ def __init__(self, integration: Integration) -> None:
13
+ super().__init__(name="google-mail", integration=integration)
14
+ self.base_api_url = "https://gmail.googleapis.com/gmail/v1/users/me"
15
+ self.base_url = "https://gmail.googleapis.com"
16
+
17
+ def send_email(
18
+ self,
19
+ to: str,
20
+ subject: str,
21
+ body: str,
22
+ body_type: str = "plain",
23
+ thread_id: str | None = None,
24
+ ) -> dict[str, Any]:
25
+ """
26
+ Sends an email using the Gmail API and returns a confirmation or error message.
27
+
28
+ Args:
29
+ to: The email address of the recipient
30
+ subject: The subject line of the email
31
+ body: The content of the email message
32
+ body_type: The MIME subtype for the body ("plain" or "html"). Defaults to "plain".
33
+ thread_id: Optional thread ID to make this a reply to an existing conversation
34
+
35
+ Returns:
36
+ A string containing either a success confirmation message or an error description
37
+
38
+ Raises:
39
+ NotAuthorizedError: When Gmail API authentication is not valid or has expired
40
+ KeyError: When required configuration keys are missing
41
+ Exception: For any other unexpected errors during the email sending process
42
+
43
+ Tags:
44
+ send, email, api, communication, important, thread, reply, openWorldHint
45
+ """
46
+
47
+ url = f"{self.base_api_url}/messages/send"
48
+ raw_message = self._create_message(to, subject, body, body_type)
49
+ email_data = {"raw": raw_message}
50
+
51
+ # Add threadId to make it a proper reply if thread_id is provided
52
+ if thread_id:
53
+ email_data["threadId"] = thread_id
54
+
55
+ response = self._post(url, email_data)
56
+
57
+ return self._handle_response(response)
58
+
59
+ def _create_message(self, to, subject, body, body_type="plain"):
60
+ try:
61
+ message = EmailMessage()
62
+ message["to"] = to
63
+ message["subject"] = subject
64
+ message["from"] = "me"
65
+ message.set_content(body, subtype=body_type)
66
+ raw = base64.urlsafe_b64encode(message.as_bytes()).decode()
67
+ return raw
68
+ except Exception as e:
69
+ logger.error(f"Error creating message: {str(e)}")
70
+ raise
71
+
72
+ def create_draft(
73
+ self,
74
+ to: str,
75
+ subject: str,
76
+ body: str,
77
+ body_type: str = "plain",
78
+ thread_id: str | None = None,
79
+ ) -> dict[str, Any]:
80
+ """
81
+ Creates a draft email message in Gmail using the Gmail API and returns a confirmation status.
82
+
83
+ Args:
84
+ to: The email address of the recipient
85
+ subject: The subject line of the draft email
86
+ body: The main content/message of the draft email
87
+ body_type: The MIME subtype for the body ("plain" or "html"). Defaults to "plain".
88
+ thread_id: Optional thread ID to make this draft a reply to an existing conversation
89
+
90
+ Returns:
91
+ A string containing either a success message with the draft ID or an error message describing the failure
92
+
93
+ Raises:
94
+ NotAuthorizedError: When the user's Gmail API authorization is invalid or expired
95
+ KeyError: When required configuration keys are missing
96
+ Exception: For general API errors, network issues, or other unexpected problems
97
+
98
+ Tags:
99
+ create, email, draft, gmail, api, important, thread, reply, html
100
+ """
101
+
102
+ url = f"{self.base_api_url}/drafts"
103
+
104
+ raw_message = self._create_message(to, subject, body, body_type)
105
+
106
+ draft_data = {"message": {"raw": raw_message}}
107
+
108
+ # Add threadId to make it a proper reply if thread_id is provided
109
+ if thread_id:
110
+ draft_data["message"]["threadId"] = thread_id
111
+
112
+ logger.info(f"Creating draft email to {to}")
113
+
114
+ response = self._post(url, draft_data)
115
+
116
+ return self._handle_response(response)
117
+
118
+ def send_draft(self, draft_id: str) -> dict[str, Any]:
119
+ """
120
+ Sends an existing draft email using the Gmail API and returns a confirmation message.
121
+
122
+ Args:
123
+ draft_id: The unique identifier of the Gmail draft to be sent
124
+
125
+ Returns:
126
+ A string containing either a success message with the sent message ID or an error message detailing the failure reason
127
+
128
+ Raises:
129
+ NotAuthorizedError: When the user's Gmail API authorization is invalid or expired
130
+ KeyError: When required configuration keys are missing from the API response
131
+ Exception: For other unexpected errors during the API request or response handling
132
+
133
+ Tags:
134
+ send, email, api, communication, important, draft
135
+ """
136
+
137
+ url = f"{self.base_api_url}/drafts/send"
138
+
139
+ draft_data = {"id": draft_id}
140
+
141
+ logger.info(f"Sending draft email with ID: {draft_id}")
142
+
143
+ response = self._post(url, draft_data)
144
+
145
+ return self._handle_response(response)
146
+
147
+ def get_draft(self, draft_id: str, format: str = "full") -> dict[str, Any]:
148
+ """
149
+ Retrieves and formats a specific draft email from Gmail by its ID
150
+
151
+ Args:
152
+ draft_id: String identifier of the draft email to retrieve
153
+ format: Output format of the draft (options: minimal, full, raw, metadata). Defaults to 'full'
154
+
155
+ Returns:
156
+ A formatted string containing the draft email details (ID, recipient, subject) or an error message if retrieval fails
157
+
158
+ Raises:
159
+ NotAuthorizedError: When the user's Gmail authorization is invalid or expired
160
+ KeyError: When required configuration keys or response data fields are missing
161
+ Exception: For any other unexpected errors during draft retrieval
162
+
163
+ Tags:
164
+ retrieve, email, gmail, draft, api, format, important
165
+ """
166
+
167
+ url = f"{self.base_api_url}/drafts/{draft_id}"
168
+
169
+ # Add format parameter as query param
170
+ params = {"format": format}
171
+
172
+ logger.info(f"Retrieving draft with ID: {draft_id}")
173
+
174
+ response = self._get(url, params=params)
175
+
176
+ return self._handle_response(response)
177
+
178
+ def list_drafts(
179
+ self,
180
+ max_results: int = 20,
181
+ q: str | None = None,
182
+ include_spam_trash: bool = False,
183
+ ) -> dict[str, Any]:
184
+ """
185
+ Retrieves and formats a list of email drafts from the user's Gmail mailbox with optional filtering and pagination.
186
+
187
+ Args:
188
+ max_results: Maximum number of drafts to return (max 500, default 20)
189
+ q: Search query string to filter drafts using Gmail search syntax (default None)
190
+ include_spam_trash: Boolean flag to include drafts from spam and trash folders (default False)
191
+
192
+ Returns:
193
+ A formatted string containing the list of draft IDs and count information, or an error message if the request fails
194
+
195
+ Raises:
196
+ NotAuthorizedError: When the Gmail API authentication is missing or invalid
197
+ KeyError: When required configuration keys are missing
198
+ Exception: For general errors during API communication or data processing
199
+
200
+ Tags:
201
+ list, email, drafts, gmail, api, search, query, pagination, important
202
+ """
203
+
204
+ url = f"{self.base_api_url}/drafts"
205
+
206
+ # Build query parameters
207
+ params: dict[str, Any] = {"maxResults": max_results}
208
+
209
+ if q:
210
+ params["q"] = q
211
+
212
+ if include_spam_trash:
213
+ params["includeSpamTrash"] = "true"
214
+
215
+ logger.info(f"Retrieving drafts list with params: {params}")
216
+
217
+ response = self._get(url, params=params)
218
+
219
+ return self._handle_response(response)
220
+
221
+ def get_message(self, message_id: str) -> dict[str, Any]:
222
+ """
223
+ Retrieves and formats a specific email message from Gmail API by its ID, including sender, recipient, date, subject, and full message body content.
224
+
225
+ Args:
226
+ message_id: The unique identifier of the Gmail message to retrieve
227
+
228
+ Returns:
229
+ A dictionary containing the cleaned message details (serializable as JSON)
230
+
231
+ Tags:
232
+ retrieve, email, format, api, gmail, message, important, body, content
233
+ """
234
+ url = f"{self.base_api_url}/messages/{message_id}"
235
+ response = self._get(url)
236
+ raw_data = self._handle_response(response)
237
+
238
+ # Extract headers
239
+ headers = {}
240
+ for header in raw_data.get("payload", {}).get("headers", []):
241
+ name = header.get("name", "")
242
+ value = header.get("value", "")
243
+ headers[name] = value
244
+
245
+ # Extract body content
246
+ body_content = self._extract_email_body(raw_data.get("payload", {}))
247
+ if not body_content:
248
+ if "snippet" in raw_data:
249
+ body_content = f"Preview: {raw_data['snippet']}"
250
+ else:
251
+ body_content = "No content available"
252
+
253
+ return {
254
+ "message_id": message_id,
255
+ "from_addr": headers.get("From", "Unknown sender"),
256
+ "to": headers.get("To", "Unknown recipient"),
257
+ "date": headers.get("Date", "Unknown date"),
258
+ "subject": headers.get("Subject", "No subject"),
259
+ "body_content": body_content,
260
+ "thread_id": raw_data.get("threadId"),
261
+ }
262
+
263
+ def _extract_email_body(self, payload):
264
+ """
265
+ Extracts the email body content from the Gmail API payload.
266
+
267
+ Args:
268
+ payload: The payload section from Gmail API response
269
+
270
+ Returns:
271
+ str: The email body content (plain text preferred, HTML as fallback)
272
+ """
273
+ try:
274
+ # Handle single part message
275
+ if payload.get("body") and payload.get("body", {}).get("data"):
276
+ return self._decode_base64(payload["body"]["data"])
277
+
278
+ # Handle multipart message
279
+ parts = payload.get("parts", [])
280
+ if not parts:
281
+ return ""
282
+
283
+ plain_text_body = ""
284
+ html_body = ""
285
+
286
+ for part in parts:
287
+ mime_type = part.get("mimeType", "")
288
+
289
+ # Extract plain text
290
+ if mime_type == "text/plain":
291
+ if part.get("body") and part.get("body", {}).get("data"):
292
+ plain_text_body = self._decode_base64(part["body"]["data"])
293
+
294
+ # Extract HTML content
295
+ elif mime_type == "text/html":
296
+ if part.get("body") and part.get("body", {}).get("data"):
297
+ html_body = self._decode_base64(part["body"]["data"])
298
+
299
+ # Handle nested multipart (recursive)
300
+ elif mime_type.startswith("multipart/") and part.get("parts"):
301
+ nested_body = self._extract_email_body(part)
302
+ if nested_body and not plain_text_body:
303
+ plain_text_body = nested_body
304
+
305
+ # Prefer plain text, fallback to HTML
306
+ if plain_text_body:
307
+ return plain_text_body
308
+ elif html_body:
309
+ return f"[HTML Content]\n{html_body}"
310
+
311
+ return ""
312
+
313
+ except Exception as e:
314
+ logger.error(f"Error extracting email body: {str(e)}")
315
+ return ""
316
+
317
+ def _decode_base64(self, data):
318
+ """
319
+ Decodes base64 URL-safe encoded data from Gmail API.
320
+
321
+ Args:
322
+ data: Base64 URL-safe encoded string
323
+
324
+ Returns:
325
+ str: Decoded string content
326
+ """
327
+ try:
328
+ # Gmail API uses URL-safe base64 encoding
329
+ decoded_bytes = base64.urlsafe_b64decode(data)
330
+ return decoded_bytes.decode("utf-8")
331
+ except Exception as e:
332
+ logger.error(f"Error decoding base64 data: {str(e)}")
333
+ return f"[Unable to decode content: {str(e)}]"
334
+
335
+ def list_messages(
336
+ self,
337
+ max_results: int = 10,
338
+ q: str | None = None,
339
+ include_spam_trash: bool = False,
340
+ page_token: str | None = None,
341
+ ) -> dict[str, Any]:
342
+ """
343
+ Retrieves and formats a list of messages from the user's Gmail mailbox with optional filtering and pagination support.
344
+
345
+ Args:
346
+ max_results: Maximum number of messages to return (max 500, default 20)
347
+ q: Search query string to filter messages using Gmail search syntax.
348
+ Examples:
349
+ - 'newer_than:1h' for emails from the last hour
350
+ - 'newer_than:1d' for emails from the last day
351
+ - 'newer_than:1w' for emails from the last week
352
+ - 'newer_than:1m' for emails from the last month
353
+ - 'newer_than:1y' for emails from the last year
354
+ - 'older_than:1h' for emails from the last hour
355
+ - 'older_than:1d' for emails from the last day
356
+ - 'older_than:1w' for emails from the last week
357
+ - 'older_than:1m' for emails from the last month
358
+ - 'older_than:1y' for emails from the last year
359
+ - 'after:2025/07/15 before:2025/07/18' for emails from July 15th to July 18th, 2025
360
+ - 'from:someone@example.com' for emails from a specific sender
361
+ - 'subject:invoice' for emails with 'invoice' in the subject
362
+ - 'has:attachment' for emails with attachments
363
+ - 'is:unread' for unread emails
364
+ include_spam_trash: Boolean flag to include messages from spam and trash folders (default False)
365
+
366
+ Returns:
367
+ A dictionary containing the list of messages and next page token for pagination
368
+
369
+ Raises:
370
+ NotAuthorizedError: When the Gmail API authentication is invalid or missing
371
+ KeyError: When required configuration keys are missing
372
+ Exception: For general API errors, network issues, or other unexpected problems
373
+
374
+ Tags:
375
+ list, messages, gmail, search, query, pagination, important
376
+ """
377
+ url = f"{self.base_api_url}/messages?format=metadata"
378
+
379
+ # Build query parameters
380
+ params: dict[str, Any] = {"maxResults": max_results}
381
+
382
+ if q:
383
+ params["q"] = q
384
+
385
+ if include_spam_trash:
386
+ params["includeSpamTrash"] = "true"
387
+
388
+ if page_token:
389
+ params["pageToken"] = page_token
390
+
391
+ logger.info(f"Retrieving messages list with params: {params}")
392
+
393
+ response = self._get(url, params=params)
394
+ data = self._handle_response(response)
395
+
396
+ # Extract message IDs
397
+ messages = data.get("messages", [])
398
+ message_ids = [msg.get("id") for msg in messages if msg.get("id")]
399
+
400
+ # Use ThreadPoolExecutor to get detailed information for each message in parallel
401
+ detailed_messages = []
402
+ if message_ids:
403
+ with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
404
+ # Submit all get_message calls
405
+ future_to_message_id = {
406
+ executor.submit(self.get_message, message_id): message_id
407
+ for message_id in message_ids
408
+ }
409
+
410
+ # Collect results as they complete
411
+ for future in concurrent.futures.as_completed(future_to_message_id):
412
+ message_id = future_to_message_id[future]
413
+ try:
414
+ result = future.result()
415
+ detailed_messages.append(result)
416
+ except Exception as e:
417
+ logger.error(f"Error retrieving message {message_id}: {str(e)}")
418
+ # Skip failed messages rather than including error strings
419
+
420
+ return {
421
+ "messages": detailed_messages,
422
+ "next_page_token": data.get("nextPageToken"),
423
+ }
424
+
425
+ def get_thread(self, thread_id: str) -> dict[str, Any]:
426
+ """
427
+ Retrieves a specific thread and all its messages from Gmail API.
428
+
429
+ Args:
430
+ thread_id: The unique identifier of the Gmail thread to retrieve
431
+
432
+ Returns:
433
+ A dictionary containing the thread details and all messages in the thread
434
+
435
+ Raises:
436
+ NotAuthorizedError: When Gmail API authentication is invalid or missing
437
+ KeyError: When required configuration keys are missing
438
+ Exception: For general errors during API communication or data processing
439
+
440
+ Tags:
441
+ retrieve, email, thread, gmail, api, conversation, important, readOnlyHint, openWorldHint
442
+ """
443
+ url = f"{self.base_api_url}/threads/{thread_id}"
444
+ logger.info(f"Retrieving thread {thread_id}")
445
+ response = self._get(url)
446
+ return self._handle_response(response)
447
+
448
+ def list_labels(self) -> dict[str, Any]:
449
+ """
450
+ Retrieves and formats a list of all labels (both system and user-created) from the user's Gmail account, organizing them by type and sorting them alphabetically.
451
+
452
+ Args:
453
+ None: This method takes no arguments
454
+
455
+ Returns:
456
+ A formatted string containing a list of Gmail labels categorized by type (system and user), with their IDs, or an error message if the operation fails.
457
+
458
+ Raises:
459
+ NotAuthorizedError: Raised when the user's Gmail authorization is invalid or missing
460
+ Exception: Raised when any other unexpected error occurs during the API request or data processing
461
+
462
+ Tags:
463
+ list, gmail, labels, fetch, organize, important, management
464
+ """
465
+
466
+ url = f"{self.base_api_url}/labels"
467
+
468
+ logger.info("Retrieving Gmail labels")
469
+
470
+ response = self._get(url)
471
+
472
+ return self._handle_response(response)
473
+
474
+ def create_label(self, name: str) -> dict[str, Any]:
475
+ """
476
+ Creates a new Gmail label with specified visibility settings and returns creation status details.
477
+
478
+ Args:
479
+ name: The display name of the label to create
480
+
481
+ Returns:
482
+ A formatted string containing the creation status, including the new label's name and ID if successful, or an error message if the creation fails
483
+
484
+ Raises:
485
+ NotAuthorizedError: Raised when the request lacks proper Gmail API authorization
486
+ Exception: Raised for any other unexpected errors during label creation
487
+
488
+ Tags:
489
+ create, label, gmail, management, important
490
+ """
491
+
492
+ url = f"{self.base_api_url}/labels"
493
+
494
+ # Create the label data with just the essential fields
495
+ label_data = {
496
+ "name": name,
497
+ "labelListVisibility": "labelShow", # Show in label list
498
+ "messageListVisibility": "show", # Show in message list
499
+ }
500
+
501
+ logger.info(f"Creating new Gmail label: {name}")
502
+
503
+ response = self._post(url, label_data)
504
+
505
+ return self._handle_response(response)
506
+
507
+ def get_profile(self) -> dict[str, Any]:
508
+ """
509
+ Retrieves and formats the user's Gmail profile information including email address, message count, thread count, and history ID.
510
+
511
+ Args:
512
+ None: This method takes no arguments besides self
513
+
514
+ Returns:
515
+ A formatted string containing the user's Gmail profile information or an error message if the request fails
516
+
517
+ Raises:
518
+ NotAuthorizedError: Raised when the user's credentials are invalid or authorization is required
519
+ Exception: Raised for any other unexpected errors during the API request or data processing
520
+
521
+ Tags:
522
+ fetch, profile, gmail, user-info, api-request, important
523
+ """
524
+
525
+ url = f"{self.base_api_url}/profile"
526
+
527
+ logger.info("Retrieving Gmail user profile")
528
+
529
+ response = self._get(url)
530
+ return self._handle_response(response)
531
+
532
+ def update_drafts(
533
+ self,
534
+ userId,
535
+ id,
536
+ access_token=None,
537
+ alt=None,
538
+ callback=None,
539
+ fields=None,
540
+ key=None,
541
+ oauth_token=None,
542
+ prettyPrint=None,
543
+ quotaUser=None,
544
+ upload_protocol=None,
545
+ uploadType=None,
546
+ xgafv=None,
547
+ message=None,
548
+ ) -> dict[str, Any]:
549
+ """
550
+ Updates an existing Gmail draft with new message content and metadata.
551
+
552
+ Args:
553
+ userId (string): userId
554
+ id (string): id
555
+ access_token (string): OAuth access token. Example: '{{access_token}}'.
556
+ alt (string): Data format for response. Example: '{{alt}}'.
557
+ callback (string): JSONP Example: '{{callback}}'.
558
+ fields (string): Selector specifying which fields to include in a partial response. Example: '{{fields}}'.
559
+ key (string): API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token. Example: '{{key}}'.
560
+ oauth_token (string): OAuth 2.0 token for the current user. Example: '{{oauth_token}}'.
561
+ prettyPrint (string): Returns response with indentations and line breaks. Example: '{{prettyPrint}}'.
562
+ quotaUser (string): Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Example: '{{quotaUser}}'.
563
+ upload_protocol (string): Upload protocol for media (e.g. "raw", "multipart"). Example: '{{upload_protocol}}'.
564
+ uploadType (string): Legacy upload protocol for media (e.g. "media", "multipart"). Example: '{{uploadType}}'.
565
+ xgafv (string): V1 error format. Example: '{{$.xgafv}}'.
566
+ message (object): message
567
+ Example:
568
+ ```json
569
+ {
570
+ "id": "elit Lorem",
571
+ "message": {
572
+ "historyId": "ullamco",
573
+ "id": "elit",
574
+ "internalDate": "dolor ullamco elit fugiat",
575
+ "labelIds": [
576
+ "incididunt et non cupidatat",
577
+ "laboris deserunt do nostrud"
578
+ ],
579
+ "payload": {
580
+ "body": {
581
+ "attachmentId": "irure",
582
+ "data": "officia laboris",
583
+ "size": -58003592
584
+ },
585
+ "filename": "laboris ad",
586
+ "headers": [
587
+ {
588
+ "name": "labore aute nisi",
589
+ "value": "reprehenderit esse ex elit"
590
+ },
591
+ {
592
+ "name": "sed",
593
+ "value": "anim ut veniam elit"
594
+ }
595
+ ],
596
+ "mimeType": "enim quis dolor aliqua veniam",
597
+ "partId": "consequat ipsum qui",
598
+ "parts": [
599
+ {
600
+ "value": "<Circular reference to #/components/schemas/MessagePart detected>"
601
+ },
602
+ {
603
+ "value": "<Circular reference to #/components/schemas/MessagePart detected>"
604
+ }
605
+ ]
606
+ },
607
+ "raw": "in enim sit pariatur",
608
+ "sizeEstimate": -74092231,
609
+ "snippet": "nostrud in",
610
+ "threadId": "enim ut ut fugiat"
611
+ }
612
+ }
613
+ ```
614
+
615
+ Returns:
616
+ dict[str, Any]: Successful response
617
+
618
+ Tags:
619
+ Drafts
620
+ """
621
+ if userId is None:
622
+ raise ValueError("Missing required parameter 'userId'")
623
+ if id is None:
624
+ raise ValueError("Missing required parameter 'id'")
625
+ request_body = {
626
+ "id": id,
627
+ "message": message,
628
+ }
629
+ request_body = {k: v for k, v in request_body.items() if v is not None}
630
+ url = f"{self.base_url}/gmail/v1/users/{userId}/drafts/{id}"
631
+ query_params = {
632
+ k: v
633
+ for k, v in [
634
+ ("access_token", access_token),
635
+ ("alt", alt),
636
+ ("callback", callback),
637
+ ("fields", fields),
638
+ ("key", key),
639
+ ("oauth_token", oauth_token),
640
+ ("prettyPrint", prettyPrint),
641
+ ("quotaUser", quotaUser),
642
+ ("upload_protocol", upload_protocol),
643
+ ("uploadType", uploadType),
644
+ ("$.xgafv", xgafv),
645
+ ]
646
+ if v is not None
647
+ }
648
+ response = self._put(url, data=request_body, params=query_params)
649
+ response.raise_for_status()
650
+ return response.json()
651
+
652
+ def trash_messsages(
653
+ self,
654
+ userId,
655
+ id,
656
+ access_token=None,
657
+ alt=None,
658
+ callback=None,
659
+ fields=None,
660
+ key=None,
661
+ oauth_token=None,
662
+ prettyPrint=None,
663
+ quotaUser=None,
664
+ upload_protocol=None,
665
+ uploadType=None,
666
+ xgafv=None,
667
+ ) -> dict[str, Any]:
668
+ """
669
+ Moves a message to the trash folder (acts like delete functionality).
670
+
671
+ Args:
672
+ userId (string): userId
673
+ id (string): id
674
+ access_token (string): OAuth access token. Example: '{{access_token}}'.
675
+ alt (string): Data format for response. Example: '{{alt}}'.
676
+ callback (string): JSONP Example: '{{callback}}'.
677
+ fields (string): Selector specifying which fields to include in a partial response. Example: '{{fields}}'.
678
+ key (string): API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token. Example: '{{key}}'.
679
+ oauth_token (string): OAuth 2.0 token for the current user. Example: '{{oauth_token}}'.
680
+ prettyPrint (string): Returns response with indentations and line breaks. Example: '{{prettyPrint}}'.
681
+ quotaUser (string): Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Example: '{{quotaUser}}'.
682
+ upload_protocol (string): Upload protocol for media (e.g. "raw", "multipart"). Example: '{{upload_protocol}}'.
683
+ uploadType (string): Legacy upload protocol for media (e.g. "media", "multipart"). Example: '{{uploadType}}'.
684
+ xgafv (string): V1 error format. Example: '{{$.xgafv}}'.
685
+
686
+ Returns:
687
+ dict[str, Any]: Successful response
688
+
689
+ Tags:
690
+ Messages, important
691
+ """
692
+ if userId is None:
693
+ raise ValueError("Missing required parameter 'userId'")
694
+ if id is None:
695
+ raise ValueError("Missing required parameter 'id'")
696
+ url = f"{self.base_url}/gmail/v1/users/{userId}/messages/{id}/trash"
697
+ query_params = {
698
+ k: v
699
+ for k, v in [
700
+ ("access_token", access_token),
701
+ ("alt", alt),
702
+ ("callback", callback),
703
+ ("fields", fields),
704
+ ("key", key),
705
+ ("oauth_token", oauth_token),
706
+ ("prettyPrint", prettyPrint),
707
+ ("quotaUser", quotaUser),
708
+ ("upload_protocol", upload_protocol),
709
+ ("uploadType", uploadType),
710
+ ("$.xgafv", xgafv),
711
+ ]
712
+ if v is not None
713
+ }
714
+ response = self._post(url, data={}, params=query_params)
715
+ response.raise_for_status()
716
+ return response.json()
717
+
718
+ def untrash_messages(
719
+ self,
720
+ userId,
721
+ id,
722
+ access_token=None,
723
+ alt=None,
724
+ callback=None,
725
+ fields=None,
726
+ key=None,
727
+ oauth_token=None,
728
+ prettyPrint=None,
729
+ quotaUser=None,
730
+ upload_protocol=None,
731
+ uploadType=None,
732
+ xgafv=None,
733
+ ) -> dict[str, Any]:
734
+ """
735
+ Moves a message out of the trash, effectively undoing a trash action and restoring the message to the user's mailbox.
736
+
737
+ Args:
738
+ userId (string): userId
739
+ id (string): id
740
+ access_token (string): OAuth access token. Example: '{{access_token}}'.
741
+ alt (string): Data format for response. Example: '{{alt}}'.
742
+ callback (string): JSONP Example: '{{callback}}'.
743
+ fields (string): Selector specifying which fields to include in a partial response. Example: '{{fields}}'.
744
+ key (string): API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token. Example: '{{key}}'.
745
+ oauth_token (string): OAuth 2.0 token for the current user. Example: '{{oauth_token}}'.
746
+ prettyPrint (string): Returns response with indentations and line breaks. Example: '{{prettyPrint}}'.
747
+ quotaUser (string): Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Example: '{{quotaUser}}'.
748
+ upload_protocol (string): Upload protocol for media (e.g. "raw", "multipart"). Example: '{{upload_protocol}}'.
749
+ uploadType (string): Legacy upload protocol for media (e.g. "media", "multipart"). Example: '{{uploadType}}'.
750
+ xgafv (string): V1 error format. Example: '{{$.xgafv}}'.
751
+
752
+ Returns:
753
+ dict[str, Any]: Successful response
754
+
755
+ Tags:
756
+ Messages
757
+ """
758
+ if userId is None:
759
+ raise ValueError("Missing required parameter 'userId'")
760
+ if id is None:
761
+ raise ValueError("Missing required parameter 'id'")
762
+ url = f"{self.base_url}/gmail/v1/users/{userId}/messages/{id}/untrash"
763
+ query_params = {
764
+ k: v
765
+ for k, v in [
766
+ ("access_token", access_token),
767
+ ("alt", alt),
768
+ ("callback", callback),
769
+ ("fields", fields),
770
+ ("key", key),
771
+ ("oauth_token", oauth_token),
772
+ ("prettyPrint", prettyPrint),
773
+ ("quotaUser", quotaUser),
774
+ ("upload_protocol", upload_protocol),
775
+ ("uploadType", uploadType),
776
+ ("$.xgafv", xgafv),
777
+ ]
778
+ if v is not None
779
+ }
780
+ response = self._post(url, data={}, params=query_params)
781
+ response.raise_for_status()
782
+ return response.json()
783
+
784
+ def get_attachments(
785
+ self,
786
+ userId,
787
+ messageId,
788
+ id,
789
+ access_token=None,
790
+ alt=None,
791
+ callback=None,
792
+ fields=None,
793
+ key=None,
794
+ oauth_token=None,
795
+ prettyPrint=None,
796
+ quotaUser=None,
797
+ upload_protocol=None,
798
+ uploadType=None,
799
+ xgafv=None,
800
+ ) -> dict[str, Any]:
801
+ """
802
+ Retrieves the actual file content of a specific attachment from a Gmail message
803
+
804
+ Args:
805
+ userId (string): userId
806
+ messageId (string): messageId
807
+ id (string): id
808
+ access_token (string): OAuth access token. Example: '{{access_token}}'.
809
+ alt (string): Data format for response. Example: '{{alt}}'.
810
+ callback (string): JSONP Example: '{{callback}}'.
811
+ fields (string): Selector specifying which fields to include in a partial response. Example: '{{fields}}'.
812
+ key (string): API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token. Example: '{{key}}'.
813
+ oauth_token (string): OAuth 2.0 token for the current user. Example: '{{oauth_token}}'.
814
+ prettyPrint (string): Returns response with indentations and line breaks. Example: '{{prettyPrint}}'.
815
+ quotaUser (string): Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Example: '{{quotaUser}}'.
816
+ upload_protocol (string): Upload protocol for media (e.g. "raw", "multipart"). Example: '{{upload_protocol}}'.
817
+ uploadType (string): Legacy upload protocol for media (e.g. "media", "multipart"). Example: '{{uploadType}}'.
818
+ xgafv (string): V1 error format. Example: '{{$.xgafv}}'.
819
+
820
+ Returns:
821
+ dict[str, Any]: Successful response
822
+
823
+ Tags:
824
+ Messages
825
+ """
826
+ if userId is None:
827
+ raise ValueError("Missing required parameter 'userId'")
828
+ if messageId is None:
829
+ raise ValueError("Missing required parameter 'messageId'")
830
+ if id is None:
831
+ raise ValueError("Missing required parameter 'id'")
832
+ url = f"{self.base_url}/gmail/v1/users/{userId}/messages/{messageId}/attachments/{id}"
833
+ query_params = {
834
+ k: v
835
+ for k, v in [
836
+ ("access_token", access_token),
837
+ ("alt", alt),
838
+ ("callback", callback),
839
+ ("fields", fields),
840
+ ("key", key),
841
+ ("oauth_token", oauth_token),
842
+ ("prettyPrint", prettyPrint),
843
+ ("quotaUser", quotaUser),
844
+ ("upload_protocol", upload_protocol),
845
+ ("uploadType", uploadType),
846
+ ("$.xgafv", xgafv),
847
+ ]
848
+ if v is not None
849
+ }
850
+ response = self._get(url, params=query_params)
851
+ response.raise_for_status()
852
+ return response.json()
853
+
854
+ def update_labels(
855
+ self,
856
+ userId,
857
+ id,
858
+ access_token=None,
859
+ alt=None,
860
+ callback=None,
861
+ fields=None,
862
+ key=None,
863
+ oauth_token=None,
864
+ prettyPrint=None,
865
+ quotaUser=None,
866
+ upload_protocol=None,
867
+ uploadType=None,
868
+ xgafv=None,
869
+ color=None,
870
+ labelListVisibility=None,
871
+ messageListVisibility=None,
872
+ messagesTotal=None,
873
+ messagesUnread=None,
874
+ name=None,
875
+ threadsTotal=None,
876
+ threadsUnread=None,
877
+ type=None,
878
+ ) -> dict[str, Any]:
879
+ """
880
+ Update an existing Gmail label's properties such as name, color, or visibility.
881
+
882
+ Args:
883
+ userId (string): userId
884
+ id (string): id
885
+ access_token (string): OAuth access token. Example: '{{access_token}}'.
886
+ alt (string): Data format for response. Example: '{{alt}}'.
887
+ callback (string): JSONP Example: '{{callback}}'.
888
+ fields (string): Selector specifying which fields to include in a partial response. Example: '{{fields}}'.
889
+ key (string): API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token. Example: '{{key}}'.
890
+ oauth_token (string): OAuth 2.0 token for the current user. Example: '{{oauth_token}}'.
891
+ prettyPrint (string): Returns response with indentations and line breaks. Example: '{{prettyPrint}}'.
892
+ quotaUser (string): Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Example: '{{quotaUser}}'.
893
+ upload_protocol (string): Upload protocol for media (e.g. "raw", "multipart"). Example: '{{upload_protocol}}'.
894
+ uploadType (string): Legacy upload protocol for media (e.g. "media", "multipart"). Example: '{{uploadType}}'.
895
+ xgafv (string): V1 error format. Example: '{{$.xgafv}}'.
896
+ color (object): color
897
+ labelListVisibility (string): labelListVisibility Example: 'labelShow'.
898
+ messageListVisibility (string): messageListVisibility Example: 'show'.
899
+ messagesTotal (number): messagesTotal Example: '-34033607'.
900
+ messagesUnread (number): messagesUnread Example: '96181517'.
901
+ name (string): name Example: 'esse nulla occaecat'.
902
+ threadsTotal (number): threadsTotal Example: '7293200'.
903
+ threadsUnread (number): threadsUnread Example: '86726755'.
904
+ type (string): type
905
+ Example:
906
+ ```json
907
+ {
908
+ "color": {
909
+ "backgroundColor": "commodo est cupidatat in sed",
910
+ "textColor": "sunt fugiat ut voluptate"
911
+ },
912
+ "id": "nostrud officia pariatur",
913
+ "labelListVisibility": "labelShow",
914
+ "messageListVisibility": "show",
915
+ "messagesTotal": -34033607,
916
+ "messagesUnread": 96181517,
917
+ "name": "esse nulla occaecat",
918
+ "threadsTotal": 7293200,
919
+ "threadsUnread": 86726755,
920
+ "type": "system"
921
+ }
922
+ ```
923
+
924
+ Returns:
925
+ dict[str, Any]: Successful response
926
+
927
+ Tags:
928
+ Labels
929
+ """
930
+ if userId is None:
931
+ raise ValueError("Missing required parameter 'userId'")
932
+ if id is None:
933
+ raise ValueError("Missing required parameter 'id'")
934
+ request_body = {
935
+ "color": color,
936
+ "id": id,
937
+ "labelListVisibility": labelListVisibility,
938
+ "messageListVisibility": messageListVisibility,
939
+ "messagesTotal": messagesTotal,
940
+ "messagesUnread": messagesUnread,
941
+ "name": name,
942
+ "threadsTotal": threadsTotal,
943
+ "threadsUnread": threadsUnread,
944
+ "type": type,
945
+ }
946
+ request_body = {k: v for k, v in request_body.items() if v is not None}
947
+ url = f"{self.base_url}/gmail/v1/users/{userId}/labels/{id}"
948
+ query_params = {
949
+ k: v
950
+ for k, v in [
951
+ ("access_token", access_token),
952
+ ("alt", alt),
953
+ ("callback", callback),
954
+ ("fields", fields),
955
+ ("key", key),
956
+ ("oauth_token", oauth_token),
957
+ ("prettyPrint", prettyPrint),
958
+ ("quotaUser", quotaUser),
959
+ ("upload_protocol", upload_protocol),
960
+ ("uploadType", uploadType),
961
+ ("$.xgafv", xgafv),
962
+ ]
963
+ if v is not None
964
+ }
965
+ response = self._put(url, data=request_body, params=query_params)
966
+ response.raise_for_status()
967
+ return response.json()
968
+
969
+ def delete_labels(
970
+ self,
971
+ userId,
972
+ id,
973
+ access_token=None,
974
+ alt=None,
975
+ callback=None,
976
+ fields=None,
977
+ key=None,
978
+ oauth_token=None,
979
+ prettyPrint=None,
980
+ quotaUser=None,
981
+ upload_protocol=None,
982
+ uploadType=None,
983
+ xgafv=None,
984
+ ) -> Any:
985
+ """
986
+ Delete a Gmail label by its ID.
987
+
988
+ Args:
989
+ userId (string): userId
990
+ id (string): id
991
+ access_token (string): OAuth access token. Example: '{{access_token}}'.
992
+ alt (string): Data format for response. Example: '{{alt}}'.
993
+ callback (string): JSONP Example: '{{callback}}'.
994
+ fields (string): Selector specifying which fields to include in a partial response. Example: '{{fields}}'.
995
+ key (string): API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token. Example: '{{key}}'.
996
+ oauth_token (string): OAuth 2.0 token for the current user. Example: '{{oauth_token}}'.
997
+ prettyPrint (string): Returns response with indentations and line breaks. Example: '{{prettyPrint}}'.
998
+ quotaUser (string): Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Example: '{{quotaUser}}'.
999
+ upload_protocol (string): Upload protocol for media (e.g. "raw", "multipart"). Example: '{{upload_protocol}}'.
1000
+ uploadType (string): Legacy upload protocol for media (e.g. "media", "multipart"). Example: '{{uploadType}}'.
1001
+ xgafv (string): V1 error format. Example: '{{$.xgafv}}'.
1002
+
1003
+ Returns:
1004
+ Any: No Content
1005
+
1006
+ Tags:
1007
+ Labels
1008
+ """
1009
+ if userId is None:
1010
+ raise ValueError("Missing required parameter 'userId'")
1011
+ if id is None:
1012
+ raise ValueError("Missing required parameter 'id'")
1013
+ url = f"{self.base_url}/gmail/v1/users/{userId}/labels/{id}"
1014
+ query_params = {
1015
+ k: v
1016
+ for k, v in [
1017
+ ("access_token", access_token),
1018
+ ("alt", alt),
1019
+ ("callback", callback),
1020
+ ("fields", fields),
1021
+ ("key", key),
1022
+ ("oauth_token", oauth_token),
1023
+ ("prettyPrint", prettyPrint),
1024
+ ("quotaUser", quotaUser),
1025
+ ("upload_protocol", upload_protocol),
1026
+ ("uploadType", uploadType),
1027
+ ("$.xgafv", xgafv),
1028
+ ]
1029
+ if v is not None
1030
+ }
1031
+ response = self._delete(url, params=query_params)
1032
+ response.raise_for_status()
1033
+ return response.json()
1034
+
1035
+ def get_filters(
1036
+ self,
1037
+ userId,
1038
+ id,
1039
+ access_token=None,
1040
+ alt=None,
1041
+ callback=None,
1042
+ fields=None,
1043
+ key=None,
1044
+ oauth_token=None,
1045
+ prettyPrint=None,
1046
+ quotaUser=None,
1047
+ upload_protocol=None,
1048
+ uploadType=None,
1049
+ xgafv=None,
1050
+ ) -> dict[str, Any]:
1051
+ """
1052
+ Fetch Gmail filter configuration and rules by filter ID
1053
+
1054
+ Args:
1055
+ userId (string): userId
1056
+ id (string): id
1057
+ access_token (string): OAuth access token. Example: '{{access_token}}'.
1058
+ alt (string): Data format for response. Example: '{{alt}}'.
1059
+ callback (string): JSONP Example: '{{callback}}'.
1060
+ fields (string): Selector specifying which fields to include in a partial response. Example: '{{fields}}'.
1061
+ key (string): API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token. Example: '{{key}}'.
1062
+ oauth_token (string): OAuth 2.0 token for the current user. Example: '{{oauth_token}}'.
1063
+ prettyPrint (string): Returns response with indentations and line breaks. Example: '{{prettyPrint}}'.
1064
+ quotaUser (string): Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Example: '{{quotaUser}}'.
1065
+ upload_protocol (string): Upload protocol for media (e.g. "raw", "multipart"). Example: '{{upload_protocol}}'.
1066
+ uploadType (string): Legacy upload protocol for media (e.g. "media", "multipart"). Example: '{{uploadType}}'.
1067
+ xgafv (string): V1 error format. Example: '{{$.xgafv}}'.
1068
+
1069
+ Returns:
1070
+ dict[str, Any]: Successful response
1071
+
1072
+ Tags:
1073
+ settings, Filters
1074
+ """
1075
+ if userId is None:
1076
+ raise ValueError("Missing required parameter 'userId'")
1077
+ if id is None:
1078
+ raise ValueError("Missing required parameter 'id'")
1079
+ url = f"{self.base_url}/gmail/v1/users/{userId}/settings/filters/{id}"
1080
+ query_params = {
1081
+ k: v
1082
+ for k, v in [
1083
+ ("access_token", access_token),
1084
+ ("alt", alt),
1085
+ ("callback", callback),
1086
+ ("fields", fields),
1087
+ ("key", key),
1088
+ ("oauth_token", oauth_token),
1089
+ ("prettyPrint", prettyPrint),
1090
+ ("quotaUser", quotaUser),
1091
+ ("upload_protocol", upload_protocol),
1092
+ ("uploadType", uploadType),
1093
+ ("$.xgafv", xgafv),
1094
+ ]
1095
+ if v is not None
1096
+ }
1097
+ response = self._get(url, params=query_params)
1098
+ response.raise_for_status()
1099
+ return response.json()
1100
+
1101
+ def delete_filters(
1102
+ self,
1103
+ userId,
1104
+ id,
1105
+ access_token=None,
1106
+ alt=None,
1107
+ callback=None,
1108
+ fields=None,
1109
+ key=None,
1110
+ oauth_token=None,
1111
+ prettyPrint=None,
1112
+ quotaUser=None,
1113
+ upload_protocol=None,
1114
+ uploadType=None,
1115
+ xgafv=None,
1116
+ ) -> Any:
1117
+ """
1118
+ Remove Gmail filter and its associated automation rules
1119
+
1120
+ Args:
1121
+ userId (string): userId
1122
+ id (string): id
1123
+ access_token (string): OAuth access token. Example: '{{access_token}}'.
1124
+ alt (string): Data format for response. Example: '{{alt}}'.
1125
+ callback (string): JSONP Example: '{{callback}}'.
1126
+ fields (string): Selector specifying which fields to include in a partial response. Example: '{{fields}}'.
1127
+ key (string): API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token. Example: '{{key}}'.
1128
+ oauth_token (string): OAuth 2.0 token for the current user. Example: '{{oauth_token}}'.
1129
+ prettyPrint (string): Returns response with indentations and line breaks. Example: '{{prettyPrint}}'.
1130
+ quotaUser (string): Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Example: '{{quotaUser}}'.
1131
+ upload_protocol (string): Upload protocol for media (e.g. "raw", "multipart"). Example: '{{upload_protocol}}'.
1132
+ uploadType (string): Legacy upload protocol for media (e.g. "media", "multipart"). Example: '{{uploadType}}'.
1133
+ xgafv (string): V1 error format. Example: '{{$.xgafv}}'.
1134
+
1135
+ Returns:
1136
+ Any: No Content
1137
+
1138
+ Tags:
1139
+ settings, Filters
1140
+ """
1141
+ if userId is None:
1142
+ raise ValueError("Missing required parameter 'userId'")
1143
+ if id is None:
1144
+ raise ValueError("Missing required parameter 'id'")
1145
+ url = f"{self.base_url}/gmail/v1/users/{userId}/settings/filters/{id}"
1146
+ query_params = {
1147
+ k: v
1148
+ for k, v in [
1149
+ ("access_token", access_token),
1150
+ ("alt", alt),
1151
+ ("callback", callback),
1152
+ ("fields", fields),
1153
+ ("key", key),
1154
+ ("oauth_token", oauth_token),
1155
+ ("prettyPrint", prettyPrint),
1156
+ ("quotaUser", quotaUser),
1157
+ ("upload_protocol", upload_protocol),
1158
+ ("uploadType", uploadType),
1159
+ ("$.xgafv", xgafv),
1160
+ ]
1161
+ if v is not None
1162
+ }
1163
+ response = self._delete(url, params=query_params)
1164
+ response.raise_for_status()
1165
+ return response.json()
1166
+
1167
+ def list_filters(
1168
+ self,
1169
+ userId,
1170
+ access_token=None,
1171
+ alt=None,
1172
+ callback=None,
1173
+ fields=None,
1174
+ key=None,
1175
+ oauth_token=None,
1176
+ prettyPrint=None,
1177
+ quotaUser=None,
1178
+ upload_protocol=None,
1179
+ uploadType=None,
1180
+ xgafv=None,
1181
+ ) -> dict[str, Any]:
1182
+ """
1183
+ Retrieve all Gmail filters and their automation settings
1184
+
1185
+ Args:
1186
+ userId (string): userId
1187
+ access_token (string): OAuth access token. Example: '{{access_token}}'.
1188
+ alt (string): Data format for response. Example: '{{alt}}'.
1189
+ callback (string): JSONP Example: '{{callback}}'.
1190
+ fields (string): Selector specifying which fields to include in a partial response. Example: '{{fields}}'.
1191
+ key (string): API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token. Example: '{{key}}'.
1192
+ oauth_token (string): OAuth 2.0 token for the current user. Example: '{{oauth_token}}'.
1193
+ prettyPrint (string): Returns response with indentations and line breaks. Example: '{{prettyPrint}}'.
1194
+ quotaUser (string): Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Example: '{{quotaUser}}'.
1195
+ upload_protocol (string): Upload protocol for media (e.g. "raw", "multipart"). Example: '{{upload_protocol}}'.
1196
+ uploadType (string): Legacy upload protocol for media (e.g. "media", "multipart"). Example: '{{uploadType}}'.
1197
+ xgafv (string): V1 error format. Example: '{{$.xgafv}}'.
1198
+
1199
+ Returns:
1200
+ dict[str, Any]: Successful response
1201
+
1202
+ Tags:
1203
+ settings, Filters
1204
+ """
1205
+ if userId is None:
1206
+ raise ValueError("Missing required parameter 'userId'")
1207
+ url = f"{self.base_url}/gmail/v1/users/{userId}/settings/filters"
1208
+ query_params = {
1209
+ k: v
1210
+ for k, v in [
1211
+ ("access_token", access_token),
1212
+ ("alt", alt),
1213
+ ("callback", callback),
1214
+ ("fields", fields),
1215
+ ("key", key),
1216
+ ("oauth_token", oauth_token),
1217
+ ("prettyPrint", prettyPrint),
1218
+ ("quotaUser", quotaUser),
1219
+ ("upload_protocol", upload_protocol),
1220
+ ("uploadType", uploadType),
1221
+ ("$.xgafv", xgafv),
1222
+ ]
1223
+ if v is not None
1224
+ }
1225
+ response = self._get(url, params=query_params)
1226
+ response.raise_for_status()
1227
+ return response.json()
1228
+
1229
+ def create_filters(
1230
+ self,
1231
+ userId,
1232
+ access_token=None,
1233
+ alt=None,
1234
+ callback=None,
1235
+ fields=None,
1236
+ key=None,
1237
+ oauth_token=None,
1238
+ prettyPrint=None,
1239
+ quotaUser=None,
1240
+ upload_protocol=None,
1241
+ uploadType=None,
1242
+ xgafv=None,
1243
+ action=None,
1244
+ criteria=None,
1245
+ id=None,
1246
+ ) -> dict[str, Any]:
1247
+ """
1248
+ Set up new Gmail filter with criteria and automated actions
1249
+
1250
+ Args:
1251
+ userId (string): userId
1252
+ access_token (string): OAuth access token. Example: '{{access_token}}'.
1253
+ alt (string): Data format for response. Example: '{{alt}}'.
1254
+ callback (string): JSONP Example: '{{callback}}'.
1255
+ fields (string): Selector specifying which fields to include in a partial response. Example: '{{fields}}'.
1256
+ key (string): API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token. Example: '{{key}}'.
1257
+ oauth_token (string): OAuth 2.0 token for the current user. Example: '{{oauth_token}}'.
1258
+ prettyPrint (string): Returns response with indentations and line breaks. Example: '{{prettyPrint}}'.
1259
+ quotaUser (string): Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters. Example: '{{quotaUser}}'.
1260
+ upload_protocol (string): Upload protocol for media (e.g. "raw", "multipart"). Example: '{{upload_protocol}}'.
1261
+ uploadType (string): Legacy upload protocol for media (e.g. "media", "multipart"). Example: '{{uploadType}}'.
1262
+ xgafv (string): V1 error format. Example: '{{$.xgafv}}'.
1263
+ action (object): action
1264
+ criteria (object): criteria
1265
+ id (string): id
1266
+ Example:
1267
+ ```json
1268
+ {
1269
+ "action": {
1270
+ "addLabelIds": [
1271
+ "nostrud laboris sed esse",
1272
+ "et ad"
1273
+ ],
1274
+ "forward": "culpa do",
1275
+ "removeLabelIds": [
1276
+ "Lorem consequat l",
1277
+ "minim Excepteur"
1278
+ ]
1279
+ },
1280
+ "criteria": {
1281
+ "excludeChats": false,
1282
+ "from": "nulla adipisicing veniam et mollit",
1283
+ "hasAttachment": true,
1284
+ "negatedQuery": "exercitation laboris",
1285
+ "query": "nulla cupidatat officia commodo laborum",
1286
+ "size": -52983385,
1287
+ "sizeComparison": "smaller",
1288
+ "subject": "sit exercitation",
1289
+ "to": "veniam commodo"
1290
+ },
1291
+ "id": "in aute anim"
1292
+ }
1293
+ ```
1294
+
1295
+ Returns:
1296
+ dict[str, Any]: Successful response
1297
+
1298
+ Tags:
1299
+ settings, Filters
1300
+ """
1301
+ if userId is None:
1302
+ raise ValueError("Missing required parameter 'userId'")
1303
+ request_body = {
1304
+ "action": action,
1305
+ "criteria": criteria,
1306
+ "id": id,
1307
+ }
1308
+ request_body = {k: v for k, v in request_body.items() if v is not None}
1309
+ url = f"{self.base_url}/gmail/v1/users/{userId}/settings/filters"
1310
+ query_params = {
1311
+ k: v
1312
+ for k, v in [
1313
+ ("access_token", access_token),
1314
+ ("alt", alt),
1315
+ ("callback", callback),
1316
+ ("fields", fields),
1317
+ ("key", key),
1318
+ ("oauth_token", oauth_token),
1319
+ ("prettyPrint", prettyPrint),
1320
+ ("quotaUser", quotaUser),
1321
+ ("upload_protocol", upload_protocol),
1322
+ ("uploadType", uploadType),
1323
+ ("$.xgafv", xgafv),
1324
+ ]
1325
+ if v is not None
1326
+ }
1327
+ response = self._post(url, data=request_body, params=query_params)
1328
+ response.raise_for_status()
1329
+ return response.json()
1330
+
1331
+ def list_tools(self):
1332
+ return [
1333
+ self.send_email,
1334
+ self.create_draft,
1335
+ self.send_draft,
1336
+ self.get_draft,
1337
+ self.list_drafts,
1338
+ self.get_message,
1339
+ self.list_messages,
1340
+ self.list_labels,
1341
+ self.create_label,
1342
+ self.get_profile,
1343
+ # Auto Generated from openapi spec
1344
+ self.update_drafts,
1345
+ self.trash_messsages,
1346
+ self.untrash_messages,
1347
+ self.get_attachments,
1348
+ self.update_labels,
1349
+ self.delete_labels,
1350
+ self.get_filters,
1351
+ self.delete_filters,
1352
+ self.list_filters,
1353
+ self.create_filters,
1354
+ ]