Skip to content

Commit 9d70ed4

Browse files
authored
Add clean conversation support (#361)
This PR adds support for the /messages/clean endpoint.
1 parent b5ca361 commit 9d70ed4

File tree

5 files changed

+143
-0
lines changed

5 files changed

+143
-0
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
nylas-python Changelog
22
======================
33

4+
Unreleased
5+
----------------
6+
* Add clean messages support
7+
48
v6.1.1
59
----------------
610
* Improved message sending and draft create/update performance

nylas/models/messages.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,56 @@ class StopScheduledMessageResponse:
198198
"""
199199

200200
message: str
201+
202+
203+
class CleanMessagesRequest(TypedDict):
204+
"""
205+
Request to clean a list of messages.
206+
207+
Attributes:
208+
message_id: IDs of the email messages to clean.
209+
ignore_links: If true, removes link-related tags (<a>) from the email message while keeping the text.
210+
ignore_images: If true, removes images from the email message.
211+
images_as_markdown: If true, converts images in the email message to Markdown.
212+
ignore_tables: If true, removes table-related tags (<table>, <th>, <td>, <tr>) from the email message while
213+
keeping rows.
214+
remove_conclusion_phrases: If true, removes phrases such as "Best" and "Regards" in the email message signature.
215+
"""
216+
217+
message_id: List[str]
218+
ignore_links: NotRequired[bool]
219+
ignore_images: NotRequired[bool]
220+
images_as_markdown: NotRequired[bool]
221+
ignore_tables: NotRequired[bool]
222+
remove_conclusion_phrases: NotRequired[bool]
223+
224+
225+
@dataclass_json
226+
@dataclass
227+
class CleanMessagesResponse(Message):
228+
"""
229+
Message object with the cleaned HTML message body.
230+
231+
Attributes:
232+
id (str): Globally unique object identifier.
233+
grant_id (str): The grant that this message belongs to.
234+
from_ (List[EmailName]): The sender of the message.
235+
date (int): The date the message was received.
236+
object: The type of object.
237+
thread_id (Optional[str]): The thread that this message belongs to.
238+
subject (Optional[str]): The subject of the message.
239+
to (Optional[List[EmailName]]): The recipients of the message.
240+
cc (Optional[List[EmailName]]): The CC recipients of the message.
241+
bcc (Optional[List[EmailName]]): The BCC recipients of the message.
242+
reply_to (Optional[List[EmailName]]): The reply-to recipients of the message.
243+
unread (Optional[bool]): Whether the message is unread.
244+
starred (Optional[bool]): Whether the message is starred.
245+
snippet (Optional[str]): A snippet of the message body.
246+
body (Optional[str]): The body of the message.
247+
attachments (Optional[List[Attachment]]): The attachments on the message.
248+
folders (Optional[List[str]]): The folders that the message is in.
249+
created_at (Optional[int]): Unix timestamp of when the message was created.
250+
conversation (str): The cleaned HTML message body.
251+
"""
252+
253+
conversation: str = ""

nylas/resources/messages.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
UpdateMessageRequest,
1515
ScheduledMessage,
1616
StopScheduledMessageResponse,
17+
CleanMessagesRequest,
18+
CleanMessagesResponse,
1719
)
1820
from nylas.models.response import Response, ListResponse, DeleteResponse
1921
from nylas.resources.smart_compose import SmartCompose
@@ -223,3 +225,24 @@ def stop_scheduled_message(
223225
)
224226

225227
return Response.from_dict(json_response, StopScheduledMessageResponse)
228+
229+
def clean_messages(
230+
self, identifier: str, request_body: CleanMessagesRequest
231+
) -> ListResponse[CleanMessagesResponse]:
232+
"""
233+
Remove extra information from a list of messages.
234+
235+
Args:
236+
identifier: The identifier of the grant to clean the message for.
237+
request_body: The values to clean the message with.
238+
239+
Returns:
240+
The list of cleaned messages.
241+
"""
242+
json_resposne = self._http_client._execute(
243+
method="PUT",
244+
path=f"/v3/grants/{identifier}/messages/clean",
245+
request_body=request_body,
246+
)
247+
248+
return ListResponse.from_dict(json_resposne, CleanMessagesResponse)

tests/conftest.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,32 @@ def http_client_list_scheduled_messages():
189189
],
190190
}
191191
return mock_http_client
192+
193+
194+
@pytest.fixture
195+
def http_client_clean_messages():
196+
mock_http_client = Mock()
197+
mock_http_client._execute.return_value = {
198+
"request_id": "dd3ec9a2-8f15-403d-b269-32b1f1beb9f5",
199+
"data": [
200+
{
201+
"body": "Hello, I just sent a message using Nylas!",
202+
"from": [
203+
{"name": "Daenerys Targaryen", "email": "daenerys.t@example.com"}
204+
],
205+
"grant_id": "41009df5-bf11-4c97-aa18-b285b5f2e386",
206+
"id": "message-1",
207+
"object": "message",
208+
"conversation": "cleaned example",
209+
},
210+
{
211+
"body": "Hello, this is a test message!",
212+
"from": [{"name": "Michael Scott", "email": "m.scott@email.com"}],
213+
"grant_id": "41009df5-bf11-4c97-aa18-b285b5f2e386",
214+
"id": "message-2",
215+
"object": "message",
216+
"conversation": "another example",
217+
},
218+
],
219+
}
220+
return mock_http_client

tests/resources/test_messages.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,3 +272,37 @@ def test_stop_scheduled_message(self, http_client_response):
272272
method="DELETE",
273273
path="/v3/grants/abc-123/messages/schedules/schedule-123",
274274
)
275+
276+
def test_clean_messages(self, http_client_clean_messages):
277+
messages = Messages(http_client_clean_messages)
278+
request_body = {
279+
"message_id": ["message-1", "message-2"],
280+
"ignore_images": True,
281+
"ignore_links": True,
282+
"ignore_tables": True,
283+
"images_as_markdown": True,
284+
"remove_conclusion_phrases": True,
285+
}
286+
287+
response = messages.clean_messages(
288+
identifier="abc-123",
289+
request_body=request_body,
290+
)
291+
292+
http_client_clean_messages._execute.assert_called_once_with(
293+
method="PUT",
294+
path="/v3/grants/abc-123/messages/clean",
295+
request_body=request_body,
296+
)
297+
298+
# Assert the conversation field, and the typical message fields serialize properly
299+
assert len(response.data) == 2
300+
assert response.data[0].body == "Hello, I just sent a message using Nylas!"
301+
assert response.data[0].from_ == [
302+
{"name": "Daenerys Targaryen", "email": "daenerys.t@example.com"}
303+
]
304+
assert response.data[0].object == "message"
305+
assert response.data[0].id == "message-1"
306+
assert response.data[0].grant_id == "41009df5-bf11-4c97-aa18-b285b5f2e386"
307+
assert response.data[0].conversation == "cleaned example"
308+
assert response.data[1].conversation == "another example"

0 commit comments

Comments
 (0)