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.
- universal_mcp/applications/ahrefs/README.md +51 -0
- universal_mcp/applications/ahrefs/__init__.py +1 -0
- universal_mcp/applications/ahrefs/app.py +2291 -0
- universal_mcp/applications/airtable/README.md +22 -0
- universal_mcp/applications/airtable/__init__.py +1 -0
- universal_mcp/applications/airtable/app.py +479 -0
- universal_mcp/applications/apollo/README.md +44 -0
- universal_mcp/applications/apollo/__init__.py +1 -0
- universal_mcp/applications/apollo/app.py +1847 -0
- universal_mcp/applications/asana/README.md +199 -0
- universal_mcp/applications/asana/__init__.py +1 -0
- universal_mcp/applications/asana/app.py +9509 -0
- universal_mcp/applications/aws-s3/README.md +0 -0
- universal_mcp/applications/aws-s3/__init__.py +1 -0
- universal_mcp/applications/aws-s3/app.py +552 -0
- universal_mcp/applications/bill/README.md +0 -0
- universal_mcp/applications/bill/__init__.py +1 -0
- universal_mcp/applications/bill/app.py +8705 -0
- universal_mcp/applications/box/README.md +307 -0
- universal_mcp/applications/box/__init__.py +1 -0
- universal_mcp/applications/box/app.py +15987 -0
- universal_mcp/applications/braze/README.md +106 -0
- universal_mcp/applications/braze/__init__.py +1 -0
- universal_mcp/applications/braze/app.py +4754 -0
- universal_mcp/applications/cal-com-v2/README.md +150 -0
- universal_mcp/applications/cal-com-v2/__init__.py +1 -0
- universal_mcp/applications/cal-com-v2/app.py +5541 -0
- universal_mcp/applications/calendly/README.md +53 -0
- universal_mcp/applications/calendly/__init__.py +1 -0
- universal_mcp/applications/calendly/app.py +1436 -0
- universal_mcp/applications/canva/README.md +43 -0
- universal_mcp/applications/canva/__init__.py +1 -0
- universal_mcp/applications/canva/app.py +941 -0
- universal_mcp/applications/clickup/README.md +135 -0
- universal_mcp/applications/clickup/__init__.py +1 -0
- universal_mcp/applications/clickup/app.py +5009 -0
- universal_mcp/applications/coda/README.md +108 -0
- universal_mcp/applications/coda/__init__.py +1 -0
- universal_mcp/applications/coda/app.py +3671 -0
- universal_mcp/applications/confluence/README.md +198 -0
- universal_mcp/applications/confluence/__init__.py +1 -0
- universal_mcp/applications/confluence/app.py +6273 -0
- universal_mcp/applications/contentful/README.md +17 -0
- universal_mcp/applications/contentful/__init__.py +1 -0
- universal_mcp/applications/contentful/app.py +364 -0
- universal_mcp/applications/crustdata/README.md +25 -0
- universal_mcp/applications/crustdata/__init__.py +1 -0
- universal_mcp/applications/crustdata/app.py +586 -0
- universal_mcp/applications/dialpad/README.md +202 -0
- universal_mcp/applications/dialpad/__init__.py +1 -0
- universal_mcp/applications/dialpad/app.py +5949 -0
- universal_mcp/applications/digitalocean/README.md +463 -0
- universal_mcp/applications/digitalocean/__init__.py +1 -0
- universal_mcp/applications/digitalocean/app.py +20835 -0
- universal_mcp/applications/domain-checker/README.md +13 -0
- universal_mcp/applications/domain-checker/__init__.py +1 -0
- universal_mcp/applications/domain-checker/app.py +265 -0
- universal_mcp/applications/e2b/README.md +12 -0
- universal_mcp/applications/e2b/__init__.py +1 -0
- universal_mcp/applications/e2b/app.py +187 -0
- universal_mcp/applications/elevenlabs/README.md +88 -0
- universal_mcp/applications/elevenlabs/__init__.py +1 -0
- universal_mcp/applications/elevenlabs/app.py +3235 -0
- universal_mcp/applications/exa/README.md +15 -0
- universal_mcp/applications/exa/__init__.py +1 -0
- universal_mcp/applications/exa/app.py +221 -0
- universal_mcp/applications/falai/README.md +17 -0
- universal_mcp/applications/falai/__init__.py +1 -0
- universal_mcp/applications/falai/app.py +331 -0
- universal_mcp/applications/figma/README.md +49 -0
- universal_mcp/applications/figma/__init__.py +1 -0
- universal_mcp/applications/figma/app.py +1090 -0
- universal_mcp/applications/firecrawl/README.md +20 -0
- universal_mcp/applications/firecrawl/__init__.py +1 -0
- universal_mcp/applications/firecrawl/app.py +514 -0
- universal_mcp/applications/fireflies/README.md +25 -0
- universal_mcp/applications/fireflies/__init__.py +1 -0
- universal_mcp/applications/fireflies/app.py +506 -0
- universal_mcp/applications/fpl/README.md +23 -0
- universal_mcp/applications/fpl/__init__.py +1 -0
- universal_mcp/applications/fpl/app.py +1327 -0
- universal_mcp/applications/fpl/utils/api.py +142 -0
- universal_mcp/applications/fpl/utils/fixtures.py +629 -0
- universal_mcp/applications/fpl/utils/helper.py +982 -0
- universal_mcp/applications/fpl/utils/league_utils.py +546 -0
- universal_mcp/applications/fpl/utils/position_utils.py +68 -0
- universal_mcp/applications/ghost-content/README.md +25 -0
- universal_mcp/applications/ghost-content/__init__.py +1 -0
- universal_mcp/applications/ghost-content/app.py +654 -0
- universal_mcp/applications/github/README.md +1049 -0
- universal_mcp/applications/github/__init__.py +1 -0
- universal_mcp/applications/github/app.py +50600 -0
- universal_mcp/applications/gong/README.md +63 -0
- universal_mcp/applications/gong/__init__.py +1 -0
- universal_mcp/applications/gong/app.py +2297 -0
- universal_mcp/applications/google-ads/README.md +0 -0
- universal_mcp/applications/google-ads/__init__.py +1 -0
- universal_mcp/applications/google-ads/app.py +23 -0
- universal_mcp/applications/google-calendar/README.md +21 -0
- universal_mcp/applications/google-calendar/__init__.py +1 -0
- universal_mcp/applications/google-calendar/app.py +574 -0
- universal_mcp/applications/google-docs/README.md +25 -0
- universal_mcp/applications/google-docs/__init__.py +1 -0
- universal_mcp/applications/google-docs/app.py +760 -0
- universal_mcp/applications/google-drive/README.md +68 -0
- universal_mcp/applications/google-drive/__init__.py +1 -0
- universal_mcp/applications/google-drive/app.py +4936 -0
- universal_mcp/applications/google-gemini/README.md +25 -0
- universal_mcp/applications/google-gemini/__init__.py +1 -0
- universal_mcp/applications/google-gemini/app.py +663 -0
- universal_mcp/applications/google-mail/README.md +31 -0
- universal_mcp/applications/google-mail/__init__.py +1 -0
- universal_mcp/applications/google-mail/app.py +1354 -0
- universal_mcp/applications/google-searchconsole/README.md +21 -0
- universal_mcp/applications/google-searchconsole/__init__.py +1 -0
- universal_mcp/applications/google-searchconsole/app.py +320 -0
- universal_mcp/applications/google-sheet/README.md +36 -0
- universal_mcp/applications/google-sheet/__init__.py +1 -0
- universal_mcp/applications/google-sheet/app.py +1941 -0
- universal_mcp/applications/hashnode/README.md +20 -0
- universal_mcp/applications/hashnode/__init__.py +1 -0
- universal_mcp/applications/hashnode/app.py +455 -0
- universal_mcp/applications/heygen/README.md +44 -0
- universal_mcp/applications/heygen/__init__.py +1 -0
- universal_mcp/applications/heygen/app.py +961 -0
- universal_mcp/applications/http-tools/README.md +16 -0
- universal_mcp/applications/http-tools/__init__.py +1 -0
- universal_mcp/applications/http-tools/app.py +153 -0
- universal_mcp/applications/hubspot/README.md +239 -0
- universal_mcp/applications/hubspot/__init__.py +1 -0
- universal_mcp/applications/hubspot/app.py +416 -0
- universal_mcp/applications/jira/README.md +600 -0
- universal_mcp/applications/jira/__init__.py +1 -0
- universal_mcp/applications/jira/app.py +28804 -0
- universal_mcp/applications/klaviyo/README.md +313 -0
- universal_mcp/applications/klaviyo/__init__.py +1 -0
- universal_mcp/applications/klaviyo/app.py +11236 -0
- universal_mcp/applications/linkedin/README.md +15 -0
- universal_mcp/applications/linkedin/__init__.py +1 -0
- universal_mcp/applications/linkedin/app.py +243 -0
- universal_mcp/applications/mailchimp/README.md +281 -0
- universal_mcp/applications/mailchimp/__init__.py +1 -0
- universal_mcp/applications/mailchimp/app.py +10937 -0
- universal_mcp/applications/markitdown/README.md +12 -0
- universal_mcp/applications/markitdown/__init__.py +1 -0
- universal_mcp/applications/markitdown/app.py +63 -0
- universal_mcp/applications/miro/README.md +151 -0
- universal_mcp/applications/miro/__init__.py +1 -0
- universal_mcp/applications/miro/app.py +5429 -0
- universal_mcp/applications/ms-teams/README.md +42 -0
- universal_mcp/applications/ms-teams/__init__.py +1 -0
- universal_mcp/applications/ms-teams/app.py +1823 -0
- universal_mcp/applications/neon/README.md +74 -0
- universal_mcp/applications/neon/__init__.py +1 -0
- universal_mcp/applications/neon/app.py +2018 -0
- universal_mcp/applications/notion/README.md +30 -0
- universal_mcp/applications/notion/__init__.py +1 -0
- universal_mcp/applications/notion/app.py +527 -0
- universal_mcp/applications/openai/README.md +22 -0
- universal_mcp/applications/openai/__init__.py +1 -0
- universal_mcp/applications/openai/app.py +759 -0
- universal_mcp/applications/outlook/README.md +20 -0
- universal_mcp/applications/outlook/__init__.py +1 -0
- universal_mcp/applications/outlook/app.py +444 -0
- universal_mcp/applications/perplexity/README.md +12 -0
- universal_mcp/applications/perplexity/__init__.py +1 -0
- universal_mcp/applications/perplexity/app.py +65 -0
- universal_mcp/applications/pipedrive/README.md +284 -0
- universal_mcp/applications/pipedrive/__init__.py +1 -0
- universal_mcp/applications/pipedrive/app.py +12924 -0
- universal_mcp/applications/posthog/README.md +132 -0
- universal_mcp/applications/posthog/__init__.py +1 -0
- universal_mcp/applications/posthog/app.py +7125 -0
- universal_mcp/applications/reddit/README.md +135 -0
- universal_mcp/applications/reddit/__init__.py +1 -0
- universal_mcp/applications/reddit/app.py +4652 -0
- universal_mcp/applications/replicate/README.md +18 -0
- universal_mcp/applications/replicate/__init__.py +1 -0
- universal_mcp/applications/replicate/app.py +495 -0
- universal_mcp/applications/resend/README.md +40 -0
- universal_mcp/applications/resend/__init__.py +1 -0
- universal_mcp/applications/resend/app.py +881 -0
- universal_mcp/applications/retell/README.md +21 -0
- universal_mcp/applications/retell/__init__.py +1 -0
- universal_mcp/applications/retell/app.py +333 -0
- universal_mcp/applications/rocketlane/README.md +70 -0
- universal_mcp/applications/rocketlane/__init__.py +1 -0
- universal_mcp/applications/rocketlane/app.py +4346 -0
- universal_mcp/applications/semanticscholar/README.md +25 -0
- universal_mcp/applications/semanticscholar/__init__.py +1 -0
- universal_mcp/applications/semanticscholar/app.py +482 -0
- universal_mcp/applications/semrush/README.md +44 -0
- universal_mcp/applications/semrush/__init__.py +1 -0
- universal_mcp/applications/semrush/app.py +2081 -0
- universal_mcp/applications/sendgrid/README.md +362 -0
- universal_mcp/applications/sendgrid/__init__.py +1 -0
- universal_mcp/applications/sendgrid/app.py +9752 -0
- universal_mcp/applications/sentry/README.md +186 -0
- universal_mcp/applications/sentry/__init__.py +1 -0
- universal_mcp/applications/sentry/app.py +7471 -0
- universal_mcp/applications/serpapi/README.md +14 -0
- universal_mcp/applications/serpapi/__init__.py +1 -0
- universal_mcp/applications/serpapi/app.py +293 -0
- universal_mcp/applications/sharepoint/README.md +0 -0
- universal_mcp/applications/sharepoint/__init__.py +1 -0
- universal_mcp/applications/sharepoint/app.py +215 -0
- universal_mcp/applications/shopify/README.md +321 -0
- universal_mcp/applications/shopify/__init__.py +1 -0
- universal_mcp/applications/shopify/app.py +15392 -0
- universal_mcp/applications/shortcut/README.md +128 -0
- universal_mcp/applications/shortcut/__init__.py +1 -0
- universal_mcp/applications/shortcut/app.py +4478 -0
- universal_mcp/applications/slack/README.md +0 -0
- universal_mcp/applications/slack/__init__.py +1 -0
- universal_mcp/applications/slack/app.py +570 -0
- universal_mcp/applications/spotify/README.md +91 -0
- universal_mcp/applications/spotify/__init__.py +1 -0
- universal_mcp/applications/spotify/app.py +2526 -0
- universal_mcp/applications/supabase/README.md +87 -0
- universal_mcp/applications/supabase/__init__.py +1 -0
- universal_mcp/applications/supabase/app.py +2970 -0
- universal_mcp/applications/tavily/README.md +12 -0
- universal_mcp/applications/tavily/__init__.py +1 -0
- universal_mcp/applications/tavily/app.py +51 -0
- universal_mcp/applications/trello/README.md +266 -0
- universal_mcp/applications/trello/__init__.py +1 -0
- universal_mcp/applications/trello/app.py +10875 -0
- universal_mcp/applications/twillo/README.md +0 -0
- universal_mcp/applications/twillo/__init__.py +1 -0
- universal_mcp/applications/twillo/app.py +269 -0
- universal_mcp/applications/twitter/README.md +100 -0
- universal_mcp/applications/twitter/__init__.py +1 -0
- universal_mcp/applications/twitter/api_segments/__init__.py +0 -0
- universal_mcp/applications/twitter/api_segments/api_segment_base.py +51 -0
- universal_mcp/applications/twitter/api_segments/compliance_api.py +122 -0
- universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +255 -0
- universal_mcp/applications/twitter/api_segments/dm_events_api.py +140 -0
- universal_mcp/applications/twitter/api_segments/likes_api.py +159 -0
- universal_mcp/applications/twitter/api_segments/lists_api.py +395 -0
- universal_mcp/applications/twitter/api_segments/openapi_json_api.py +34 -0
- universal_mcp/applications/twitter/api_segments/spaces_api.py +309 -0
- universal_mcp/applications/twitter/api_segments/trends_api.py +40 -0
- universal_mcp/applications/twitter/api_segments/tweets_api.py +1403 -0
- universal_mcp/applications/twitter/api_segments/usage_api.py +40 -0
- universal_mcp/applications/twitter/api_segments/users_api.py +1498 -0
- universal_mcp/applications/twitter/app.py +46 -0
- universal_mcp/applications/unipile/README.md +28 -0
- universal_mcp/applications/unipile/__init__.py +1 -0
- universal_mcp/applications/unipile/app.py +829 -0
- universal_mcp/applications/whatsapp/README.md +23 -0
- universal_mcp/applications/whatsapp/__init__.py +1 -0
- universal_mcp/applications/whatsapp/app.py +595 -0
- universal_mcp/applications/whatsapp-business/README.md +34 -0
- universal_mcp/applications/whatsapp-business/__init__.py +1 -0
- universal_mcp/applications/whatsapp-business/app.py +1065 -0
- universal_mcp/applications/wrike/README.md +46 -0
- universal_mcp/applications/wrike/__init__.py +1 -0
- universal_mcp/applications/wrike/app.py +1583 -0
- universal_mcp/applications/youtube/README.md +57 -0
- universal_mcp/applications/youtube/__init__.py +1 -0
- universal_mcp/applications/youtube/app.py +1696 -0
- universal_mcp/applications/zenquotes/README.md +12 -0
- universal_mcp/applications/zenquotes/__init__.py +1 -0
- universal_mcp/applications/zenquotes/app.py +31 -0
- universal_mcp_applications-0.1.1.dist-info/METADATA +172 -0
- universal_mcp_applications-0.1.1.dist-info/RECORD +268 -0
- universal_mcp_applications-0.1.1.dist-info/WHEEL +4 -0
- universal_mcp_applications-0.1.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,881 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from universal_mcp.applications.application import APIApplication
|
|
4
|
+
from universal_mcp.exceptions import NotAuthorizedError, ToolError
|
|
5
|
+
from universal_mcp.integrations import Integration
|
|
6
|
+
|
|
7
|
+
import resend
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ResendApp(APIApplication):
|
|
11
|
+
def __init__(self, integration: Integration, **kwargs: Any) -> None:
|
|
12
|
+
super().__init__(name="resend", integration=integration, **kwargs)
|
|
13
|
+
self._api_key = None
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def api_key(self) -> str:
|
|
17
|
+
if self._api_key is None:
|
|
18
|
+
if not self.integration:
|
|
19
|
+
raise NotAuthorizedError("Resend integration not configured.")
|
|
20
|
+
credentials = self.integration.get_credentials()
|
|
21
|
+
api_key = (
|
|
22
|
+
credentials.get("api_key")
|
|
23
|
+
or credentials.get("API_KEY")
|
|
24
|
+
or credentials.get("apiKey")
|
|
25
|
+
)
|
|
26
|
+
if not api_key:
|
|
27
|
+
raise NotAuthorizedError("Resend API key not found in credentials.")
|
|
28
|
+
self._api_key = api_key
|
|
29
|
+
resend.api_key = self._api_key
|
|
30
|
+
return self._api_key
|
|
31
|
+
|
|
32
|
+
def send_email(
|
|
33
|
+
self,
|
|
34
|
+
from_email: str,
|
|
35
|
+
to_emails: list[str],
|
|
36
|
+
subject: str,
|
|
37
|
+
text: str,
|
|
38
|
+
) -> dict[str, Any]:
|
|
39
|
+
"""
|
|
40
|
+
Sends an email to specified recipients using the Resend API.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
from_email: The email address to send the email from in this format:- Ankit <ankit@agentr.dev>
|
|
44
|
+
to_emails: A list of email addresses to send the email to.
|
|
45
|
+
subject: The subject of the email.
|
|
46
|
+
text: The text content of the email.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
A dictionary containing the response from the Resend API.
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
ToolError: If the email fails to send due to an API error.
|
|
53
|
+
|
|
54
|
+
Tags:
|
|
55
|
+
send, email, api, communication, important
|
|
56
|
+
"""
|
|
57
|
+
self.api_key
|
|
58
|
+
params: resend.Emails.SendParams = {
|
|
59
|
+
"from": from_email,
|
|
60
|
+
"to": to_emails,
|
|
61
|
+
"subject": subject,
|
|
62
|
+
"text": text,
|
|
63
|
+
}
|
|
64
|
+
try:
|
|
65
|
+
email = resend.Emails.send(params)
|
|
66
|
+
return email
|
|
67
|
+
except Exception as e:
|
|
68
|
+
raise ToolError(f"Failed to send email: {e}")
|
|
69
|
+
|
|
70
|
+
def send_batch_emails(
|
|
71
|
+
self,
|
|
72
|
+
emails: list[dict[str, Any]],
|
|
73
|
+
) -> dict[str, Any]:
|
|
74
|
+
"""
|
|
75
|
+
Sends a batch of emails using the Resend API.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
emails: A list of dictionaries containing parameters for individual emails, such as `from`, `to`, `subject`, `html`, and `text`.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
A dictionary containing the response from the Resend API.
|
|
82
|
+
|
|
83
|
+
Raises:
|
|
84
|
+
ToolError: If the batch email sending fails or if the number of emails is not between 1 and 100.
|
|
85
|
+
|
|
86
|
+
Tags:
|
|
87
|
+
batch, send, emails, resend-api
|
|
88
|
+
"""
|
|
89
|
+
self.api_key
|
|
90
|
+
if not 1 <= len(emails) <= 100:
|
|
91
|
+
raise ToolError(
|
|
92
|
+
"The number of emails in a batch must be between 1 and 100."
|
|
93
|
+
)
|
|
94
|
+
params: list[resend.Emails.SendParams] = emails
|
|
95
|
+
try:
|
|
96
|
+
sent_emails_response = resend.Batch.send(params)
|
|
97
|
+
return sent_emails_response
|
|
98
|
+
except Exception as e:
|
|
99
|
+
raise ToolError(f"Failed to send batch emails: {e}")
|
|
100
|
+
|
|
101
|
+
def get_email(self, email_id: str) -> dict[str, Any]:
|
|
102
|
+
"""
|
|
103
|
+
Retrieves a single email by its specified ID.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
email_id: The unique identifier of the email to retrieve.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
A dictionary containing the details of the retrieved email.
|
|
110
|
+
|
|
111
|
+
Raises:
|
|
112
|
+
ToolError: Raised if the retrieval of the email fails due to an internal error.
|
|
113
|
+
|
|
114
|
+
Tags:
|
|
115
|
+
retrieve, email, management
|
|
116
|
+
"""
|
|
117
|
+
self.api_key
|
|
118
|
+
try:
|
|
119
|
+
email = resend.Emails.get(email_id=email_id)
|
|
120
|
+
return email
|
|
121
|
+
except Exception as e:
|
|
122
|
+
raise ToolError(f"Failed to retrieve email: {e}")
|
|
123
|
+
|
|
124
|
+
def update_scheduled_email(
|
|
125
|
+
self, email_id: str, scheduled_at: str
|
|
126
|
+
) -> dict[str, Any]:
|
|
127
|
+
"""
|
|
128
|
+
Updates the scheduling of an email to a new time.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
email_id: The ID of the email to update.
|
|
132
|
+
scheduled_at: The new scheduled time in ISO 8601 format.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
A dictionary containing the response from the Resend API.
|
|
136
|
+
|
|
137
|
+
Raises:
|
|
138
|
+
ToolError: If updating the scheduled email fails.
|
|
139
|
+
|
|
140
|
+
Tags:
|
|
141
|
+
update, email, async_job, management
|
|
142
|
+
"""
|
|
143
|
+
self.api_key
|
|
144
|
+
params: resend.Emails.UpdateParams = {
|
|
145
|
+
"id": email_id,
|
|
146
|
+
"scheduled_at": scheduled_at,
|
|
147
|
+
}
|
|
148
|
+
try:
|
|
149
|
+
response = resend.Emails.update(params=params)
|
|
150
|
+
return response
|
|
151
|
+
except Exception as e:
|
|
152
|
+
raise ToolError(f"Failed to update scheduled email: {e}")
|
|
153
|
+
|
|
154
|
+
def cancel_scheduled_email(self, email_id: str) -> dict[str, Any]:
|
|
155
|
+
"""
|
|
156
|
+
Cancels a scheduled email using the provided email ID.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
email_id: The ID of the scheduled email to cancel.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
A dictionary containing the response from the Resend API.
|
|
163
|
+
|
|
164
|
+
Raises:
|
|
165
|
+
ToolError: If canceling the scheduled email fails.
|
|
166
|
+
|
|
167
|
+
Tags:
|
|
168
|
+
cancel, email, management
|
|
169
|
+
"""
|
|
170
|
+
self.api_key
|
|
171
|
+
try:
|
|
172
|
+
response = resend.Emails.cancel(email_id=email_id)
|
|
173
|
+
return response
|
|
174
|
+
except Exception as e:
|
|
175
|
+
raise ToolError(f"Failed to cancel scheduled email: {e}")
|
|
176
|
+
|
|
177
|
+
def create_domain(self, name: str) -> dict[str, Any]:
|
|
178
|
+
"""
|
|
179
|
+
Creates a new domain with the specified name.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
name: The name of the domain to create (e.g., 'example.com')
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
A dictionary containing the created domain object and its details.
|
|
186
|
+
|
|
187
|
+
Raises:
|
|
188
|
+
ToolError: If the domain creation fails due to API errors or invalid input.
|
|
189
|
+
|
|
190
|
+
Tags:
|
|
191
|
+
create, domain, management, api, batch, important
|
|
192
|
+
"""
|
|
193
|
+
self.api_key
|
|
194
|
+
params: resend.Domains.CreateParams = {"name": name}
|
|
195
|
+
try:
|
|
196
|
+
domain = resend.Domains.create(params)
|
|
197
|
+
return domain
|
|
198
|
+
except Exception as e:
|
|
199
|
+
raise ToolError(f"Failed to create domain: {e}")
|
|
200
|
+
|
|
201
|
+
def get_domain(self, domain_id: str) -> dict[str, Any]:
|
|
202
|
+
"""
|
|
203
|
+
Retrieves a single domain by its ID.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
domain_id: The ID of the domain to retrieve.
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
A dictionary containing the domain object.
|
|
210
|
+
|
|
211
|
+
Raises:
|
|
212
|
+
ToolError: Raised if the domain retrieval fails.
|
|
213
|
+
|
|
214
|
+
Tags:
|
|
215
|
+
retrieve, domain, management
|
|
216
|
+
"""
|
|
217
|
+
self.api_key
|
|
218
|
+
try:
|
|
219
|
+
domain = resend.Domains.get(domain_id=domain_id)
|
|
220
|
+
return domain
|
|
221
|
+
except Exception as e:
|
|
222
|
+
raise ToolError(f"Failed to retrieve domain: {e}")
|
|
223
|
+
|
|
224
|
+
def verify_domain(self, domain_id: str) -> dict[str, Any]:
|
|
225
|
+
"""
|
|
226
|
+
Verifies an existing domain using the provided domain ID.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
domain_id: The ID of the domain to verify.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
A dictionary containing the response from the domain verification API.
|
|
233
|
+
|
|
234
|
+
Raises:
|
|
235
|
+
ToolError: If the domain verification process fails.
|
|
236
|
+
|
|
237
|
+
Tags:
|
|
238
|
+
verify, domain
|
|
239
|
+
"""
|
|
240
|
+
self.api_key
|
|
241
|
+
try:
|
|
242
|
+
response = resend.Domains.verify(domain_id=domain_id)
|
|
243
|
+
return response
|
|
244
|
+
except Exception as e:
|
|
245
|
+
raise ToolError(f"Failed to verify domain: {e}")
|
|
246
|
+
|
|
247
|
+
def update_domain(
|
|
248
|
+
self,
|
|
249
|
+
domain_id: str,
|
|
250
|
+
open_tracking: bool | None = None,
|
|
251
|
+
click_tracking: bool | None = None,
|
|
252
|
+
tls: str | None = None,
|
|
253
|
+
) -> dict[str, Any]:
|
|
254
|
+
"""
|
|
255
|
+
Updates an existing domain's settings regarding open tracking, click tracking, and TLS enforcement.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
domain_id: The ID of the domain to update.
|
|
259
|
+
open_tracking: Enable or disable open tracking.
|
|
260
|
+
click_tracking: Enable or disable click tracking.
|
|
261
|
+
tls: The TLS enforcement policy (enforced or opportunistic).
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
A dictionary containing the updated domain object.
|
|
265
|
+
|
|
266
|
+
Raises:
|
|
267
|
+
ToolError: Raised if updating the domain fails.
|
|
268
|
+
|
|
269
|
+
Tags:
|
|
270
|
+
update, domain, management
|
|
271
|
+
"""
|
|
272
|
+
self.api_key
|
|
273
|
+
params: resend.Domains.UpdateParams = {"id": domain_id}
|
|
274
|
+
if open_tracking is not None:
|
|
275
|
+
params["open_tracking"] = open_tracking
|
|
276
|
+
if click_tracking is not None:
|
|
277
|
+
params["click_tracking"] = click_tracking
|
|
278
|
+
if tls is not None:
|
|
279
|
+
params["tls"] = tls
|
|
280
|
+
try:
|
|
281
|
+
updated_domain = resend.Domains.update(params)
|
|
282
|
+
return updated_domain
|
|
283
|
+
except Exception as e:
|
|
284
|
+
raise ToolError(f"Failed to update domain: {e}")
|
|
285
|
+
|
|
286
|
+
def list_domains(self) -> list[dict[str, Any]]:
|
|
287
|
+
"""
|
|
288
|
+
Retrieves a list of all domains for the authenticated user.
|
|
289
|
+
|
|
290
|
+
Returns:
|
|
291
|
+
A list of dictionaries, each representing a domain.
|
|
292
|
+
|
|
293
|
+
Raises:
|
|
294
|
+
ToolError: If listing the domains fails.
|
|
295
|
+
|
|
296
|
+
Tags:
|
|
297
|
+
list, domains, important, management
|
|
298
|
+
"""
|
|
299
|
+
self.api_key
|
|
300
|
+
try:
|
|
301
|
+
domains = resend.Domains.list()
|
|
302
|
+
return domains
|
|
303
|
+
except Exception as e:
|
|
304
|
+
raise ToolError(f"Failed to list domains: {e}")
|
|
305
|
+
|
|
306
|
+
def remove_domain(self, domain_id: str) -> dict[str, Any]:
|
|
307
|
+
"""
|
|
308
|
+
Removes an existing domain by its ID using the Resend API.
|
|
309
|
+
|
|
310
|
+
Args:
|
|
311
|
+
domain_id: The unique identifier of the domain to be removed.
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
A dictionary containing the response from the Resend API after attempting to remove the domain.
|
|
315
|
+
|
|
316
|
+
Raises:
|
|
317
|
+
ToolError: Raised if the operation to remove the domain fails, including if the API call encounters an error.
|
|
318
|
+
|
|
319
|
+
Tags:
|
|
320
|
+
remove, management, api, domain
|
|
321
|
+
"""
|
|
322
|
+
self.api_key
|
|
323
|
+
try:
|
|
324
|
+
response = resend.Domains.remove(domain_id=domain_id)
|
|
325
|
+
return response
|
|
326
|
+
except Exception as e:
|
|
327
|
+
raise ToolError(f"Failed to remove domain: {e}")
|
|
328
|
+
|
|
329
|
+
def create_api_key(self, name: str) -> dict[str, Any]:
|
|
330
|
+
"""
|
|
331
|
+
Creates a new API key for authenticating with Resend.
|
|
332
|
+
|
|
333
|
+
Args:
|
|
334
|
+
name: The name of the API key (e.g., 'Production').
|
|
335
|
+
|
|
336
|
+
Returns:
|
|
337
|
+
A dictionary containing the new API key object.
|
|
338
|
+
|
|
339
|
+
Raises:
|
|
340
|
+
ToolError: Raised if API key creation fails.
|
|
341
|
+
|
|
342
|
+
Tags:
|
|
343
|
+
create, api-key, authentication
|
|
344
|
+
"""
|
|
345
|
+
self.api_key
|
|
346
|
+
params: resend.ApiKeys.CreateParams = {"name": name}
|
|
347
|
+
try:
|
|
348
|
+
api_key_obj = resend.ApiKeys.create(params)
|
|
349
|
+
return api_key_obj
|
|
350
|
+
except Exception as e:
|
|
351
|
+
raise ToolError(f"Failed to create API key: {e}")
|
|
352
|
+
|
|
353
|
+
def list_api_keys(self) -> list[dict[str, Any]]:
|
|
354
|
+
"""
|
|
355
|
+
Retrieves a list of all API keys available through the resend service.
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
None: This function takes no arguments.
|
|
359
|
+
|
|
360
|
+
Returns:
|
|
361
|
+
List of dictionaries, each representing an API key with associated details.
|
|
362
|
+
|
|
363
|
+
Raises:
|
|
364
|
+
ToolError: If there is a failure when attempting to list the API keys, typically due to an underlying exception from the resend API.
|
|
365
|
+
|
|
366
|
+
Tags:
|
|
367
|
+
list, api, important
|
|
368
|
+
"""
|
|
369
|
+
self.api_key
|
|
370
|
+
try:
|
|
371
|
+
keys = resend.ApiKeys.list()
|
|
372
|
+
return keys
|
|
373
|
+
except Exception as e:
|
|
374
|
+
raise ToolError(f"Failed to list API keys: {e}")
|
|
375
|
+
|
|
376
|
+
def remove_api_key(self, api_key_id: str) -> dict[str, Any]:
|
|
377
|
+
"""
|
|
378
|
+
Removes an existing API key using the specified key ID.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
api_key_id: The ID of the API key to remove.
|
|
382
|
+
|
|
383
|
+
Returns:
|
|
384
|
+
A dictionary containing the response from the Resend API after removing the API key.
|
|
385
|
+
|
|
386
|
+
Raises:
|
|
387
|
+
ToolError: Raised if removing the API key fails, including any underlying errors.
|
|
388
|
+
|
|
389
|
+
Tags:
|
|
390
|
+
remove, api-key, management
|
|
391
|
+
"""
|
|
392
|
+
self.api_key
|
|
393
|
+
try:
|
|
394
|
+
response = resend.ApiKeys.remove(api_key_id=api_key_id)
|
|
395
|
+
return response
|
|
396
|
+
except Exception as e:
|
|
397
|
+
raise ToolError(f"Failed to remove API key: {e}")
|
|
398
|
+
|
|
399
|
+
def create_broadcast(
|
|
400
|
+
self,
|
|
401
|
+
audience_id: str,
|
|
402
|
+
from_email: str,
|
|
403
|
+
subject: str,
|
|
404
|
+
html: str,
|
|
405
|
+
) -> dict[str, Any]:
|
|
406
|
+
"""
|
|
407
|
+
Creates a new broadcast to send to a specified audience.
|
|
408
|
+
|
|
409
|
+
Args:
|
|
410
|
+
audience_id: The ID of the audience to send the broadcast to.
|
|
411
|
+
from_email: The sender's email address.
|
|
412
|
+
subject: The subject line of the broadcast.
|
|
413
|
+
html: The HTML content of the broadcast. Use {{{...}}} for merge tags.
|
|
414
|
+
|
|
415
|
+
Returns:
|
|
416
|
+
A dictionary containing the created broadcast object.
|
|
417
|
+
|
|
418
|
+
Raises:
|
|
419
|
+
ToolError: Raised if creating the broadcast fails due to an underlying exception.
|
|
420
|
+
|
|
421
|
+
Tags:
|
|
422
|
+
broadcast, email, important
|
|
423
|
+
"""
|
|
424
|
+
self.api_key
|
|
425
|
+
params: resend.Broadcasts.CreateParams = {
|
|
426
|
+
"audience_id": audience_id,
|
|
427
|
+
"from": from_email,
|
|
428
|
+
"subject": subject,
|
|
429
|
+
"html": html,
|
|
430
|
+
}
|
|
431
|
+
try:
|
|
432
|
+
broadcast = resend.Broadcasts.create(params)
|
|
433
|
+
return broadcast
|
|
434
|
+
except Exception as e:
|
|
435
|
+
raise ToolError(f"Failed to create broadcast: {e}")
|
|
436
|
+
|
|
437
|
+
def get_broadcast(self, broadcast_id: str) -> dict[str, Any]:
|
|
438
|
+
"""
|
|
439
|
+
Retrieves a single broadcast by its ID.
|
|
440
|
+
|
|
441
|
+
Args:
|
|
442
|
+
broadcast_id: The ID of the broadcast to retrieve.
|
|
443
|
+
|
|
444
|
+
Returns:
|
|
445
|
+
A dictionary containing the broadcast object.
|
|
446
|
+
|
|
447
|
+
Raises:
|
|
448
|
+
ToolError: Raised if retrieving the broadcast fails.
|
|
449
|
+
|
|
450
|
+
Tags:
|
|
451
|
+
retrieve, broadcast
|
|
452
|
+
"""
|
|
453
|
+
self.api_key
|
|
454
|
+
try:
|
|
455
|
+
broadcast = resend.Broadcasts.get(id=broadcast_id)
|
|
456
|
+
return broadcast
|
|
457
|
+
except Exception as e:
|
|
458
|
+
raise ToolError(f"Failed to retrieve broadcast: {e}")
|
|
459
|
+
|
|
460
|
+
def update_broadcast(
|
|
461
|
+
self,
|
|
462
|
+
broadcast_id: str,
|
|
463
|
+
html: str | None = None,
|
|
464
|
+
subject: str | None = None,
|
|
465
|
+
) -> dict[str, Any]:
|
|
466
|
+
"""
|
|
467
|
+
Updates a broadcast by modifying its HTML content and/or subject line.
|
|
468
|
+
|
|
469
|
+
Args:
|
|
470
|
+
broadcast_id: The ID of the broadcast to update.
|
|
471
|
+
html: The new HTML content for the broadcast.
|
|
472
|
+
subject: The new subject line for the broadcast.
|
|
473
|
+
|
|
474
|
+
Returns:
|
|
475
|
+
A dictionary containing the updated broadcast object.
|
|
476
|
+
|
|
477
|
+
Raises:
|
|
478
|
+
ToolError: Raised if updating the broadcast fails or no update fields are provided.
|
|
479
|
+
|
|
480
|
+
Tags:
|
|
481
|
+
update, management, broadcast, api
|
|
482
|
+
"""
|
|
483
|
+
self.api_key
|
|
484
|
+
params: resend.Broadcasts.UpdateParams = {"id": broadcast_id}
|
|
485
|
+
if html is not None:
|
|
486
|
+
params["html"] = html
|
|
487
|
+
if subject is not None:
|
|
488
|
+
params["subject"] = subject
|
|
489
|
+
if len(params) == 1:
|
|
490
|
+
raise ToolError(
|
|
491
|
+
"At least one field (e.g., html, subject) must be provided for the update."
|
|
492
|
+
)
|
|
493
|
+
try:
|
|
494
|
+
updated_broadcast = resend.Broadcasts.update(params)
|
|
495
|
+
return updated_broadcast
|
|
496
|
+
except Exception as e:
|
|
497
|
+
raise ToolError(f"Failed to update broadcast: {e}")
|
|
498
|
+
|
|
499
|
+
def send_broadcast(
|
|
500
|
+
self, broadcast_id: str, scheduled_at: str | None = None
|
|
501
|
+
) -> dict[str, Any]:
|
|
502
|
+
"""
|
|
503
|
+
Starts sending a broadcast via the API.
|
|
504
|
+
|
|
505
|
+
Args:
|
|
506
|
+
broadcast_id: The ID of the broadcast to send.
|
|
507
|
+
scheduled_at: The time to send the broadcast, e.g., 'in 1 min' or an ISO 8601 datetime.
|
|
508
|
+
|
|
509
|
+
Returns:
|
|
510
|
+
A dictionary containing the response from the Resend API.
|
|
511
|
+
|
|
512
|
+
Raises:
|
|
513
|
+
ToolError: If sending the broadcast fails.
|
|
514
|
+
|
|
515
|
+
Tags:
|
|
516
|
+
broadcast, send, api, management
|
|
517
|
+
"""
|
|
518
|
+
self.api_key
|
|
519
|
+
params: resend.Broadcasts.SendParams = {"broadcast_id": broadcast_id}
|
|
520
|
+
if scheduled_at:
|
|
521
|
+
params["scheduled_at"] = scheduled_at
|
|
522
|
+
try:
|
|
523
|
+
response = resend.Broadcasts.send(params)
|
|
524
|
+
return response
|
|
525
|
+
except Exception as e:
|
|
526
|
+
raise ToolError(f"Failed to send broadcast: {e}")
|
|
527
|
+
|
|
528
|
+
def remove_broadcast(self, broadcast_id: str) -> dict[str, Any]:
|
|
529
|
+
"""
|
|
530
|
+
Removes an existing broadcast with 'draft' status.
|
|
531
|
+
|
|
532
|
+
Args:
|
|
533
|
+
broadcast_id: The ID of the broadcast to remove.
|
|
534
|
+
|
|
535
|
+
Returns:
|
|
536
|
+
A dictionary containing the response from the Resend API.
|
|
537
|
+
|
|
538
|
+
Raises:
|
|
539
|
+
ToolError: If removing the broadcast fails.
|
|
540
|
+
|
|
541
|
+
Tags:
|
|
542
|
+
remove, broadcast, api-management, draft-status
|
|
543
|
+
"""
|
|
544
|
+
self.api_key
|
|
545
|
+
try:
|
|
546
|
+
response = resend.Broadcasts.remove(id=broadcast_id)
|
|
547
|
+
return response
|
|
548
|
+
except Exception as e:
|
|
549
|
+
raise ToolError(f"Failed to remove broadcast: {e}")
|
|
550
|
+
|
|
551
|
+
def list_broadcasts(self) -> list[dict[str, Any]]:
|
|
552
|
+
"""
|
|
553
|
+
Retrieves a list of all available broadcasts using the configured API key.
|
|
554
|
+
|
|
555
|
+
Returns:
|
|
556
|
+
A list of dictionaries, each representing a broadcast with its attributes.
|
|
557
|
+
|
|
558
|
+
Raises:
|
|
559
|
+
ToolError: If listing broadcasts fails due to a connection, API, or other retrieval error.
|
|
560
|
+
|
|
561
|
+
Tags:
|
|
562
|
+
list, broadcast, api, management, important
|
|
563
|
+
"""
|
|
564
|
+
self.api_key
|
|
565
|
+
try:
|
|
566
|
+
broadcasts = resend.Broadcasts.list()
|
|
567
|
+
return broadcasts
|
|
568
|
+
except Exception as e:
|
|
569
|
+
raise ToolError(f"Failed to list broadcasts: {e}")
|
|
570
|
+
|
|
571
|
+
def create_audience(self, name: str) -> dict[str, Any]:
|
|
572
|
+
"""
|
|
573
|
+
Creates a new audience (a list of contacts) with the specified name.
|
|
574
|
+
|
|
575
|
+
Args:
|
|
576
|
+
name: The name of the audience (e.g., "Registered Users").
|
|
577
|
+
|
|
578
|
+
Returns:
|
|
579
|
+
A dictionary containing the created audience object.
|
|
580
|
+
|
|
581
|
+
Raises:
|
|
582
|
+
ToolError: If creating the audience fails due to an underlying error.
|
|
583
|
+
|
|
584
|
+
Tags:
|
|
585
|
+
create, audience, management, important
|
|
586
|
+
"""
|
|
587
|
+
self.api_key
|
|
588
|
+
params: resend.Audiences.CreateParams = {"name": name}
|
|
589
|
+
try:
|
|
590
|
+
audience = resend.Audiences.create(params)
|
|
591
|
+
return audience
|
|
592
|
+
except Exception as e:
|
|
593
|
+
raise ToolError(f"Failed to create audience: {e}")
|
|
594
|
+
|
|
595
|
+
def get_audience(self, audience_id: str) -> dict[str, Any]:
|
|
596
|
+
"""
|
|
597
|
+
Retrieves a single audience object from the API using the specified audience ID.
|
|
598
|
+
|
|
599
|
+
Args:
|
|
600
|
+
audience_id: The unique identifier of the audience to retrieve.
|
|
601
|
+
|
|
602
|
+
Returns:
|
|
603
|
+
A dictionary containing all data for the requested audience object.
|
|
604
|
+
|
|
605
|
+
Raises:
|
|
606
|
+
ToolError: If retrieving the audience from the API fails, with a message describing the error.
|
|
607
|
+
|
|
608
|
+
Tags:
|
|
609
|
+
fetch, audience, management, api
|
|
610
|
+
"""
|
|
611
|
+
self.api_key
|
|
612
|
+
try:
|
|
613
|
+
audience = resend.Audiences.get(id=audience_id)
|
|
614
|
+
return audience
|
|
615
|
+
except Exception as e:
|
|
616
|
+
raise ToolError(f"Failed to retrieve audience: {e}")
|
|
617
|
+
|
|
618
|
+
def remove_audience(self, audience_id: str) -> dict[str, Any]:
|
|
619
|
+
"""
|
|
620
|
+
Removes an existing audience using the provided audience ID and returns the API response.
|
|
621
|
+
|
|
622
|
+
Args:
|
|
623
|
+
audience_id: The unique identifier of the audience to remove.
|
|
624
|
+
|
|
625
|
+
Returns:
|
|
626
|
+
A dictionary containing the response from the Resend API.
|
|
627
|
+
|
|
628
|
+
Raises:
|
|
629
|
+
ToolError: Raised if removing the audience fails due to API error or other issues.
|
|
630
|
+
|
|
631
|
+
Tags:
|
|
632
|
+
remove, audience, management, api
|
|
633
|
+
"""
|
|
634
|
+
self.api_key
|
|
635
|
+
try:
|
|
636
|
+
response = resend.Audiences.remove(id=audience_id)
|
|
637
|
+
return response
|
|
638
|
+
except Exception as e:
|
|
639
|
+
raise ToolError(f"Failed to remove audience: {e}")
|
|
640
|
+
|
|
641
|
+
def list_audiences(self) -> list[dict[str, Any]]:
|
|
642
|
+
"""
|
|
643
|
+
Retrieves a list of all audiences.
|
|
644
|
+
|
|
645
|
+
Returns:
|
|
646
|
+
A list of dictionaries, each representing an audience.
|
|
647
|
+
|
|
648
|
+
Raises:
|
|
649
|
+
ToolError: Raised if listing the audiences fails due to an internal error.
|
|
650
|
+
|
|
651
|
+
Tags:
|
|
652
|
+
list, audiences, management, important
|
|
653
|
+
"""
|
|
654
|
+
self.api_key
|
|
655
|
+
try:
|
|
656
|
+
audiences = resend.Audiences.list()
|
|
657
|
+
return audiences
|
|
658
|
+
except Exception as e:
|
|
659
|
+
raise ToolError(f"Failed to list audiences: {e}")
|
|
660
|
+
|
|
661
|
+
def create_contact(
|
|
662
|
+
self,
|
|
663
|
+
audience_id: str,
|
|
664
|
+
email: str,
|
|
665
|
+
first_name: str | None = None,
|
|
666
|
+
last_name: str | None = None,
|
|
667
|
+
unsubscribed: bool = False,
|
|
668
|
+
) -> dict[str, Any]:
|
|
669
|
+
"""
|
|
670
|
+
Creates a contact within a specific audience.
|
|
671
|
+
|
|
672
|
+
Args:
|
|
673
|
+
audience_id: The ID of the audience to add the contact to.
|
|
674
|
+
email: The email address of the contact.
|
|
675
|
+
first_name: The contact's first name.
|
|
676
|
+
last_name: The contact's last name.
|
|
677
|
+
unsubscribed: The contact's subscription status.
|
|
678
|
+
|
|
679
|
+
Returns:
|
|
680
|
+
A dictionary containing the created contact's ID.
|
|
681
|
+
|
|
682
|
+
Raises:
|
|
683
|
+
ToolError: Raised if creating the contact fails.
|
|
684
|
+
|
|
685
|
+
Tags:
|
|
686
|
+
create, contact, management, important
|
|
687
|
+
"""
|
|
688
|
+
self.api_key
|
|
689
|
+
params: resend.Contacts.CreateParams = {
|
|
690
|
+
"audience_id": audience_id,
|
|
691
|
+
"email": email,
|
|
692
|
+
"unsubscribed": unsubscribed,
|
|
693
|
+
}
|
|
694
|
+
if first_name:
|
|
695
|
+
params["first_name"] = first_name
|
|
696
|
+
if last_name:
|
|
697
|
+
params["last_name"] = last_name
|
|
698
|
+
try:
|
|
699
|
+
contact = resend.Contacts.create(params)
|
|
700
|
+
return contact
|
|
701
|
+
except Exception as e:
|
|
702
|
+
raise ToolError(f"Failed to create contact: {e}")
|
|
703
|
+
|
|
704
|
+
def get_contact(
|
|
705
|
+
self, audience_id: str, contact_id: str | None = None, email: str | None = None
|
|
706
|
+
) -> dict[str, Any]:
|
|
707
|
+
"""
|
|
708
|
+
Retrieves a single contact from an audience by providing either a unique contact ID or an email address, ensuring exactly one identifier is given.
|
|
709
|
+
|
|
710
|
+
Args:
|
|
711
|
+
audience_id: The ID of the audience in which to search for the contact.
|
|
712
|
+
contact_id: The unique ID of the contact, if available. Exactly one of 'contact_id' or 'email' must be provided.
|
|
713
|
+
email: The email address of the contact, if available. Exactly one of 'contact_id' or 'email' must be provided.
|
|
714
|
+
|
|
715
|
+
Returns:
|
|
716
|
+
A dictionary containing the retrieved contact object, with details such as ID, email, and other contact attributes.
|
|
717
|
+
|
|
718
|
+
Raises:
|
|
719
|
+
ToolError: Raised if neither 'contact_id' nor 'email' is provided, if both are provided (ambiguous identifier), or if retrieval from the API fails.
|
|
720
|
+
|
|
721
|
+
Tags:
|
|
722
|
+
retrieve, contact, audience, management, api
|
|
723
|
+
"""
|
|
724
|
+
self.api_key
|
|
725
|
+
if not (contact_id or email) or (contact_id and email):
|
|
726
|
+
raise ToolError("You must provide exactly one of 'contact_id' or 'email'.")
|
|
727
|
+
params = {"audience_id": audience_id}
|
|
728
|
+
if contact_id:
|
|
729
|
+
params["id"] = contact_id
|
|
730
|
+
if email:
|
|
731
|
+
params["email"] = email
|
|
732
|
+
try:
|
|
733
|
+
contact = resend.Contacts.get(**params)
|
|
734
|
+
return contact
|
|
735
|
+
except Exception as e:
|
|
736
|
+
raise ToolError(f"Failed to retrieve contact: {e}")
|
|
737
|
+
|
|
738
|
+
def update_contact(
|
|
739
|
+
self,
|
|
740
|
+
audience_id: str,
|
|
741
|
+
contact_id: str | None = None,
|
|
742
|
+
email: str | None = None,
|
|
743
|
+
first_name: str | None = None,
|
|
744
|
+
last_name: str | None = None,
|
|
745
|
+
unsubscribed: bool | None = None,
|
|
746
|
+
) -> dict[str, Any]:
|
|
747
|
+
"""
|
|
748
|
+
Updates an existing contact, identified by ID or email, within a specified audience.
|
|
749
|
+
|
|
750
|
+
Args:
|
|
751
|
+
audience_id: The ID of the audience containing the contact.
|
|
752
|
+
contact_id: The ID of the contact to update.
|
|
753
|
+
email: The email of the contact to update.
|
|
754
|
+
first_name: The new first name for the contact.
|
|
755
|
+
last_name: The new last name for the contact.
|
|
756
|
+
unsubscribed: The new subscription status for the contact.
|
|
757
|
+
|
|
758
|
+
Returns:
|
|
759
|
+
A dictionary containing the response from the Resend API.
|
|
760
|
+
|
|
761
|
+
Raises:
|
|
762
|
+
ToolError: Raised if the update fails, if an identifier is missing, or if no update fields are provided.
|
|
763
|
+
|
|
764
|
+
Tags:
|
|
765
|
+
update, contact, management
|
|
766
|
+
"""
|
|
767
|
+
self.api_key
|
|
768
|
+
if not (contact_id or email) or (contact_id and email):
|
|
769
|
+
raise ToolError(
|
|
770
|
+
"You must provide exactly one of 'contact_id' or 'email' to identify the contact."
|
|
771
|
+
)
|
|
772
|
+
params: resend.Contacts.UpdateParams = {"audience_id": audience_id}
|
|
773
|
+
if contact_id:
|
|
774
|
+
params["id"] = contact_id
|
|
775
|
+
if email:
|
|
776
|
+
params["email"] = email
|
|
777
|
+
if first_name is not None:
|
|
778
|
+
params["first_name"] = first_name
|
|
779
|
+
if last_name is not None:
|
|
780
|
+
params["last_name"] = last_name
|
|
781
|
+
if unsubscribed is not None:
|
|
782
|
+
params["unsubscribed"] = unsubscribed
|
|
783
|
+
if len(params) <= 2: # Only audience_id and one identifier
|
|
784
|
+
raise ToolError(
|
|
785
|
+
"At least one field to update (e.g., first_name, unsubscribed) must be provided."
|
|
786
|
+
)
|
|
787
|
+
try:
|
|
788
|
+
response = resend.Contacts.update(params)
|
|
789
|
+
return response
|
|
790
|
+
except Exception as e:
|
|
791
|
+
raise ToolError(f"Failed to update contact: {e}")
|
|
792
|
+
|
|
793
|
+
def remove_contact(
|
|
794
|
+
self, audience_id: str, contact_id: str | None = None, email: str | None = None
|
|
795
|
+
) -> dict[str, Any]:
|
|
796
|
+
"""
|
|
797
|
+
Removes a contact from an audience, identified by ID or email.
|
|
798
|
+
|
|
799
|
+
Args:
|
|
800
|
+
audience_id: The ID of the audience.
|
|
801
|
+
contact_id: The ID of the contact to remove.
|
|
802
|
+
email: The email of the contact to remove.
|
|
803
|
+
|
|
804
|
+
Returns:
|
|
805
|
+
A dictionary containing the response from the Resend API.
|
|
806
|
+
|
|
807
|
+
Raises:
|
|
808
|
+
ToolError: If contact removal fails, or if the contact identifier is missing or ambiguous.
|
|
809
|
+
|
|
810
|
+
Tags:
|
|
811
|
+
remove, contact-management, api-call
|
|
812
|
+
"""
|
|
813
|
+
self.api_key
|
|
814
|
+
if not (contact_id or email) or (contact_id and email):
|
|
815
|
+
raise ToolError("You must provide exactly one of 'contact_id' or 'email'.")
|
|
816
|
+
params = {"audience_id": audience_id}
|
|
817
|
+
if contact_id:
|
|
818
|
+
params["id"] = contact_id
|
|
819
|
+
if email:
|
|
820
|
+
params["email"] = email
|
|
821
|
+
try:
|
|
822
|
+
response = resend.Contacts.remove(**params)
|
|
823
|
+
return response
|
|
824
|
+
except Exception as e:
|
|
825
|
+
raise ToolError(f"Failed to remove contact: {e}")
|
|
826
|
+
|
|
827
|
+
def list_contacts(self, audience_id: str) -> list[dict[str, Any]]:
|
|
828
|
+
"""
|
|
829
|
+
Lists all contacts from a specified audience.
|
|
830
|
+
|
|
831
|
+
Args:
|
|
832
|
+
audience_id: The ID of the audience whose contacts you want to list.
|
|
833
|
+
|
|
834
|
+
Returns:
|
|
835
|
+
A list of dictionaries, each representing a contact in the audience.
|
|
836
|
+
|
|
837
|
+
Raises:
|
|
838
|
+
ToolError: Raised if listing the contacts fails.
|
|
839
|
+
|
|
840
|
+
Tags:
|
|
841
|
+
list, contacts, management, important
|
|
842
|
+
"""
|
|
843
|
+
self.api_key
|
|
844
|
+
try:
|
|
845
|
+
contacts = resend.Contacts.list(audience_id=audience_id)
|
|
846
|
+
return contacts
|
|
847
|
+
except Exception as e:
|
|
848
|
+
raise ToolError(f"Failed to list contacts: {e}")
|
|
849
|
+
|
|
850
|
+
def list_tools(self) -> list[callable]:
|
|
851
|
+
return [
|
|
852
|
+
self.send_email,
|
|
853
|
+
self.send_batch_emails,
|
|
854
|
+
self.get_email,
|
|
855
|
+
self.update_scheduled_email,
|
|
856
|
+
self.cancel_scheduled_email,
|
|
857
|
+
self.create_domain,
|
|
858
|
+
self.get_domain,
|
|
859
|
+
self.verify_domain,
|
|
860
|
+
self.update_domain,
|
|
861
|
+
self.list_domains,
|
|
862
|
+
self.remove_domain,
|
|
863
|
+
self.create_api_key,
|
|
864
|
+
self.list_api_keys,
|
|
865
|
+
self.remove_api_key,
|
|
866
|
+
self.create_broadcast,
|
|
867
|
+
self.get_broadcast,
|
|
868
|
+
self.update_broadcast,
|
|
869
|
+
self.send_broadcast,
|
|
870
|
+
self.remove_broadcast,
|
|
871
|
+
self.list_broadcasts,
|
|
872
|
+
self.create_audience,
|
|
873
|
+
self.get_audience,
|
|
874
|
+
self.remove_audience,
|
|
875
|
+
self.list_audiences,
|
|
876
|
+
self.create_contact,
|
|
877
|
+
self.get_contact,
|
|
878
|
+
self.update_contact,
|
|
879
|
+
self.remove_contact,
|
|
880
|
+
self.list_contacts,
|
|
881
|
+
]
|