Skip to content

Commit 53e0d8d

Browse files
Ol1ver0413nitpicker55555fengju0213
authored
feat: Integrate Resend to Camel (#3096)
Co-authored-by: Puzhen Zhang <91596298+nitpicker55555@users.noreply.github.com> Co-authored-by: Sun Tao <2605127667@qq.com>
1 parent 6d420c9 commit 53e0d8d

File tree

6 files changed

+568
-1
lines changed

6 files changed

+568
-1
lines changed

camel/toolkits/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
from .aci_toolkit import ACIToolkit
7777
from .origene_mcp_toolkit import OrigeneToolkit
7878
from .playwright_mcp_toolkit import PlaywrightMCPToolkit
79+
from .resend_toolkit import ResendToolkit
7980
from .wolfram_alpha_toolkit import WolframAlphaToolkit
8081
from .task_planning_toolkit import TaskPlanningToolkit
8182
from .hybrid_browser_toolkit import HybridBrowserToolkit
@@ -155,6 +156,7 @@
155156
'KlavisToolkit',
156157
'ACIToolkit',
157158
'PlaywrightMCPToolkit',
159+
'ResendToolkit',
158160
'WolframAlphaToolkit',
159161
'BohriumToolkit',
160162
'OpenAIImageToolkit', # Backward compatibility

camel/toolkits/resend_toolkit.py

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14+
15+
from typing import Dict, List, Optional, cast
16+
17+
from camel.toolkits.base import BaseToolkit
18+
from camel.toolkits.function_tool import FunctionTool
19+
from camel.utils import MCPServer, api_keys_required
20+
21+
22+
@MCPServer()
23+
class ResendToolkit(BaseToolkit):
24+
r"""A toolkit for sending emails using the Resend API.
25+
26+
This toolkit provides functionality to send emails using Resend's
27+
Python SDK.It supports sending both HTML and plain text emails,
28+
with options for multiple recipients, CC, BCC, reply-to
29+
addresses, and custom headers.
30+
31+
Notes:
32+
To use this toolkit, you need to set the following environment
33+
variable:
34+
- RESEND_API_KEY: Your Resend API key. You can get one from
35+
https://resend.com/api-keys
36+
37+
Example:
38+
.. code-block:: python
39+
40+
from camel.toolkits import ResendToolkit
41+
42+
# Initialize the toolkit
43+
toolkit = ResendToolkit()
44+
45+
# Get tools
46+
tools = toolkit.get_tools()
47+
"""
48+
49+
@api_keys_required([(None, "RESEND_API_KEY")])
50+
def send_email(
51+
self,
52+
to: List[str],
53+
subject: str,
54+
from_email: str,
55+
html: Optional[str] = None,
56+
text: Optional[str] = None,
57+
cc: Optional[List[str]] = None,
58+
bcc: Optional[List[str]] = None,
59+
reply_to: Optional[str] = None,
60+
tags: Optional[List[Dict[str, str]]] = None,
61+
headers: Optional[Dict[str, str]] = None,
62+
) -> str:
63+
r"""Send an email using the Resend API.
64+
65+
Args:
66+
to (List[str]): List of recipient email addresses.
67+
subject (str): The email subject line.
68+
from_email (str): The sender email address. Must be from a verified
69+
domain.
70+
html (Optional[str]): The HTML content of the email. Either html or
71+
text must be provided. (default: :obj:`None`)
72+
text (Optional[str]): The plain text content of the email. Either
73+
html or text must be provided. (default: :obj:`None`)
74+
cc (Optional[List[str]]): List of CC recipient email addresses.
75+
(default: :obj:`None`)
76+
bcc (Optional[List[str]]): List of BCC recipient email addresses.
77+
(default: :obj:`None`)
78+
reply_to (Optional[str]): The reply-to email address.
79+
(default: :obj:`None`)
80+
tags (Optional[List[Dict[str, str]]]): List of tags to attach to
81+
the email. Each tag should be a dict with 'name' and
82+
'value' keys. (default: :obj:`None`)
83+
headers (Optional[Dict[str, str]]): Custom headers to include in
84+
the email.(default: :obj:`None`)
85+
86+
Returns:
87+
str: A success message with the email ID if sent successfully,
88+
or an error message if the send failed.
89+
90+
Raises:
91+
ValueError: If neither html nor text content is provided.
92+
93+
Example:
94+
.. code-block:: python
95+
96+
toolkit = ResendToolkit()
97+
result = toolkit.send_email(
98+
to=["recipient@example.com"],
99+
subject="Hello World",
100+
from_email="sender@yourdomain.com",
101+
html="<h1>Hello, World!</h1>",
102+
text="Hello, World!"
103+
)
104+
"""
105+
import os
106+
107+
if not html and not text:
108+
raise ValueError(
109+
"Either 'html' or 'text' content must be provided"
110+
)
111+
112+
try:
113+
import resend
114+
except ImportError:
115+
raise ImportError(
116+
"Please install the resend package first. "
117+
"You can install it by running `pip install resend`."
118+
)
119+
120+
# Set the API key
121+
resend.api_key = os.getenv("RESEND_API_KEY")
122+
123+
# Prepare email parameters
124+
params: resend.Emails.SendParams = {
125+
"from": from_email,
126+
"to": to,
127+
"subject": subject,
128+
}
129+
130+
# Add content
131+
if html:
132+
params["html"] = html
133+
if text:
134+
params["text"] = text
135+
136+
# Add optional parameters
137+
if cc:
138+
params["cc"] = cc
139+
if bcc:
140+
params["bcc"] = bcc
141+
if reply_to:
142+
params["reply_to"] = reply_to
143+
if tags:
144+
params["tags"] = cast('list[resend.emails._tag.Tag]', tags)
145+
if headers:
146+
params["headers"] = headers
147+
148+
try:
149+
# Send the email
150+
email = resend.Emails.send(params)
151+
return (
152+
f"Email sent successfully. "
153+
f"Email ID: {email.get('id', 'Unknown')}"
154+
)
155+
except Exception as e:
156+
return f"Failed to send email: {e!s}"
157+
158+
def get_tools(self) -> List[FunctionTool]:
159+
r"""Returns a list of FunctionTool objects representing the
160+
functions in the toolkit.
161+
162+
Returns:
163+
List[FunctionTool]: A list of FunctionTool objects
164+
representing the functions in the toolkit.
165+
"""
166+
return [
167+
FunctionTool(self.send_email),
168+
]
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. =========
14+
from camel.agents import ChatAgent
15+
from camel.models import ModelFactory
16+
from camel.toolkits import ResendToolkit
17+
from camel.types import ModelPlatformType, ModelType
18+
19+
20+
def main():
21+
# Initialize ResendToolkit
22+
resend_toolkit = ResendToolkit()
23+
24+
# Create model
25+
model = ModelFactory.create(
26+
model_platform=ModelPlatformType.DEFAULT,
27+
model_type=ModelType.DEFAULT,
28+
)
29+
30+
# Create agent with ResendToolkit
31+
agent = ChatAgent(
32+
system_message="You are an email assistant. "
33+
"Help send emails using the ResendToolkit.The sender email is "
34+
"onboarding@resend.dev",
35+
model=model,
36+
tools=resend_toolkit.get_tools(),
37+
)
38+
39+
# Example 1: Send a simple HTML email
40+
print("=" * 50)
41+
print("Example 1: HTML Email")
42+
print("=" * 50)
43+
response = agent.step(
44+
"Send an email to user@example.com with subject 'Welcome to CAMEL AI' "
45+
"and HTML content '<h1>Welcome!</h1><p>Thank you for joining "
46+
"CAMEL AI.</p>' from onboarding@resend.dev"
47+
)
48+
print(response.msg.content)
49+
50+
# Example 2: Send email with CC
51+
print("\n" + "=" * 50)
52+
print("Example 2: Email with CC")
53+
print("=" * 50)
54+
response = agent.step(
55+
"Send an email to user1@example.com with CC to user2@example.com "
56+
"with subject 'CAMEL AI Test Email' and text content "
57+
"'This is a test email from CAMEL AI ResendToolkit.' "
58+
"from onboarding@resend.dev"
59+
)
60+
print(response.msg.content)
61+
62+
# Example 3: Send email with both HTML and text content
63+
print("\n" + "=" * 50)
64+
print("Example 3: Newsletter Email")
65+
print("=" * 50)
66+
response = agent.step(
67+
"Send an email to user@example.com with subject 'Weekly Newsletter' "
68+
"from onboarding@resend.dev with HTML content "
69+
"'<h2>Newsletter</h2><p>Here are this week updates.</p>' "
70+
"and plain text content 'Newsletter\n\nHere are this week updates.'"
71+
)
72+
print(response.msg.content)
73+
74+
75+
if __name__ == "__main__":
76+
main()
77+
78+
"""
79+
==================================================
80+
Example 1: HTML Email
81+
==================================================
82+
Your email has been sent successfully.
83+
84+
Details:
85+
- To: user@example.com
86+
- From: onboarding@resend.dev
87+
- Subject: Welcome to CAMEL AI
88+
- Content type: HTML
89+
- Email ID: 92fd****b683
90+
91+
==================================================
92+
Example 2: Email with CC
93+
==================================================
94+
Your email has been sent successfully.
95+
96+
Details:
97+
- To: user1@example.com
98+
- CC: user2@example.com
99+
- From: onboarding@resend.dev
100+
- Subject: CAMEL AI Test Email
101+
- Content type: Text
102+
- Email ID: b0e3****0211
103+
104+
==================================================
105+
Example 3: Newsletter Email
106+
==================================================
107+
Your email has been sent successfully.
108+
109+
Details:
110+
- To: user@example.com
111+
- From: onboarding@resend.dev
112+
- Subject: Weekly Newsletter
113+
- Content types: HTML and Plain Text
114+
- Email ID: 9bd0****86b1
115+
"""

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ communication_tools = [
147147
"discord.py>=2.3.2,<3",
148148
"notion-client>=2.2.1,<3",
149149
"praw>=7.7.1,<8",
150+
"resend>=2.0.0,<3",
150151
]
151152
data_tools = [
152153
"numpy>=1.2,<=2.2",
@@ -344,6 +345,7 @@ all = [
344345
"ipykernel>=6.0.0,<7",
345346
"agentops>=0.3.21,<0.4",
346347
"praw>=7.7.1,<8",
348+
"resend>=2.0.0,<3",
347349
"textblob>=0.17.1,<0.18",
348350
"scholarly[tor]==1.7.11",
349351
"notion-client>=2.2.1,<3",
@@ -597,6 +599,7 @@ module = [
597599
"arxiv",
598600
"arxiv2text",
599601
"praw",
602+
"resend",
600603
"textblob",
601604
"datacommons",
602605
"datacommons_pandas",

0 commit comments

Comments
 (0)