From 006d025c5253ab8d80b4f58f41f03e4eef308d5a Mon Sep 17 00:00:00 2001 From: Ted Meyer Date: Thu, 30 May 2024 12:45:39 +0200 Subject: [PATCH 1/4] Send custom headers as internetMessageHeaders Example in the documentation https://learn.microsoft.com/en-us/graph/api/user-post-messages?view=graph-rest-1.0&tabs=http#example-2-create-message-draft-that-includes-custom-message-headers --- O365/message.py | 3 +++ tests/test_message.py | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/O365/message.py b/O365/message.py index 3b7ba459..865b6ac6 100644 --- a/O365/message.py +++ b/O365/message.py @@ -686,6 +686,9 @@ def to_api_data(self, restrict_keys=None): # this property does not form part of the message itself message[cc('parentFolderId')] = self.folder_id + if self.message_headers: + message[cc('internetMessageHeaders')] = self.message_headers + if restrict_keys: for key in list(message.keys()): if key not in restrict_keys: diff --git a/tests/test_message.py b/tests/test_message.py index 8afd0376..1ff60859 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -211,6 +211,25 @@ def test_save_draft_with_with_large_attachment_when_object_id_is_set(self): assert msg.con.calls[2].payload == b"conte" assert msg.con.calls[3].payload == b"nt" + def test_save_draft_with_custom_header(self): + msg = message() + msg.subject = "Test" + my_custom_header = [{"name": "x-my-custom-header", "value": "myHeaderValue"}] + msg.message_headers = my_custom_header + + assert msg.save_draft() is True + [call] = msg.con.calls + assert call.url == self.base_url + "me/mailFolders/Drafts/messages" + assert call.payload == { + "body": {"content": "", "contentType": "HTML"}, + "flag": {"flagStatus": "notFlagged"}, + "importance": "normal", + "isDeliveryReceiptRequested": False, + "isReadReceiptRequested": False, + "subject": "Test", + "internetMessageHeaders": my_custom_header, + } + def test_save_message(self): msg = message(__cloud_data__={"id": "123", "isDraft": False}) msg.subject = "Changed" @@ -291,6 +310,25 @@ def test_send(self): "saveToSentItems": False, } + def test_send_with_headers(self): + my_testheader = {"x-my-custom-header": "some_value"} + msg = message(__cloud_data__={"internetMessageHeaders": [my_testheader]}) + assert msg.send(save_to_sent_folder=False) + [call] = msg.con.calls + assert call.url == self.base_url + "me/sendMail" + assert call.payload == { + "message": { + "body": {"content": "", "contentType": "HTML"}, + "flag": {"flagStatus": "notFlagged"}, + "importance": "normal", + "isDeliveryReceiptRequested": False, + "isReadReceiptRequested": False, + "subject": "", + "internetMessageHeaders": [my_testheader], + }, + "saveToSentItems": False, + } + def test_send_existing_object(self): msg = message(__cloud_data__={"id": "123"}) assert msg.send() From dd77f043ebb453189756b85a9aca449ccbbe0a90 Mon Sep 17 00:00:00 2001 From: Ted Meyer Date: Thu, 30 May 2024 12:46:42 +0200 Subject: [PATCH 2/4] Track changes of message_headers --- O365/message.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/O365/message.py b/O365/message.py index 865b6ac6..f722220b 100644 --- a/O365/message.py +++ b/O365/message.py @@ -340,7 +340,7 @@ def __init__(self, *, parent=None, con=None, **kwargs): self.web_link = cloud_data.get(cc('webLink'), '') # Headers only retrieved when selecting 'internetMessageHeaders' - self.message_headers = cloud_data.get(cc('internetMessageHeaders'), []) + self.__message_headers = cloud_data.get(cc('internetMessageHeaders'), []) def __str__(self): return self.__repr__() @@ -622,6 +622,20 @@ def single_value_extended_properties(self): """ singleValueExtendedProperties """ return self.__single_value_extended_properties + @property + def message_headers(self): + """ Custom message headers + List of internetMessageHeaders, see definition: https://learn.microsoft.com/en-us/graph/api/resources/internetmessageheader?view=graph-rest-1.0 + :type: list[dict[str, str]] + """ + + return self.__message_headers + + @message_headers.setter + def message_headers(self, value): + self.__message_headers = value + self._track_changes.add('message_headers') + def to_api_data(self, restrict_keys=None): """ Returns a dict representation of this message prepared to be sent to the cloud From f9f42c3b1311d459344b112ec64fc676459a8c35 Mon Sep 17 00:00:00 2001 From: Ted Meyer Date: Mon, 10 Jun 2024 10:34:52 +0200 Subject: [PATCH 3/4] message_headers needs to be a list --- O365/message.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/O365/message.py b/O365/message.py index f722220b..36635e3a 100644 --- a/O365/message.py +++ b/O365/message.py @@ -633,6 +633,9 @@ def message_headers(self): @message_headers.setter def message_headers(self, value): + if not isinstance(value, list): + raise ValueError('"message_header" must be a list') + self.__message_headers = value self._track_changes.add('message_headers') From ae9b3620a5c7b7662af47b677e06265a2171e700 Mon Sep 17 00:00:00 2001 From: Ted Meyer Date: Mon, 10 Jun 2024 10:54:28 +0200 Subject: [PATCH 4/4] Add an add function to message_header This to offload from the users the need to know the exact format of the datastructure (having a list of dicts with specific keys). --- O365/message.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/O365/message.py b/O365/message.py index 36635e3a..61ffb787 100644 --- a/O365/message.py +++ b/O365/message.py @@ -639,6 +639,14 @@ def message_headers(self, value): self.__message_headers = value self._track_changes.add('message_headers') + def add_message_header(self, name, value): + # Look if we already have the key. If we do, update it, otherwise write + for header in self.__message_headers: + if header["name"] == name: + header["value"] = value + return + self.__message_headers.append({"name": name, "value": value}) + def to_api_data(self, restrict_keys=None): """ Returns a dict representation of this message prepared to be sent to the cloud