class Message
Represents an email message in a Microsoft Outlook mailbox folder, providing methods for message operations like sending, replying, forwarding, and managing attachments.
/tf/active/vicechatdev/SPFCsync/venv/lib64/python3.11/site-packages/office365/outlook/mail/messages/message.py
27 - 483
complex
Purpose
The Message class is a comprehensive representation of an Outlook email message that extends OutlookItem. It provides full lifecycle management for email messages including creation, modification, sending, replying, forwarding, and attachment handling. It supports both simple operations (send, reply) and advanced features (extended properties, MIME content download, resumable uploads for large attachments). The class integrates with Microsoft Graph API through a context object and uses a query-based pattern for API operations.
Source Code
class Message(OutlookItem):
"""A message in a mailbox folder."""
def add_extended_property(self, name, value):
# type: (str, str) -> Self
"""Create a single-value extended property for a message"""
prop_id = str(uuid.uuid4())
prop_type = "String"
prop_value = [
{
"id": "{0} {{{1}}} Name {2}".format(prop_type, prop_id, name),
"value": value,
}
]
self.set_property("singleValueExtendedProperties", prop_value)
return self
def create_forward(self, to_recipients=None, message=None, comment=None):
"""
Create a draft to forward an existing message, in either JSON or MIME format.
:param list[Recipient] to_recipients:
:param Message message:
:param str comment:
"""
return_type = Message(self.context)
payload = {
"ToRecipients": ClientValueCollection(Recipient, to_recipients),
"Message": message,
"Comment": comment,
}
qry = ServiceOperationQuery(
self, "createForward", None, payload, None, return_type
)
self.context.add_query(qry)
return self
def download(self, file_object):
# type: (IO) -> Self
"""Download MIME content of a message into a file"""
def _save_content(return_type):
# type: (ClientResult[AnyStr]) -> None
file_object.write(return_type.value)
self.get_content().after_execute(_save_content)
return self
def get_content(self):
# type: () -> ClientResult[AnyStr]
"""Get MIME content of a message"""
return_type = ClientResult(self.context)
qry = FunctionQuery(self, "$value", None, return_type)
self.context.add_query(qry)
return return_type
def add_file_attachment(
self, name, content=None, content_type=None, base64_content=None
):
"""
Attach a file to message
:param str name: The name representing the text that is displayed below the icon representing the
embedded attachment
:param str or None content: The contents of the file
:param str or None content_type: The content type of the attachment.
:param str or None base64_content: The contents of the file in the form of a base64 string.
"""
if not content and not base64_content:
raise TypeError("Either content or base64_content is required")
self.attachments.add_file(name, content, content_type, base64_content)
return self
def upload_attachment(self, file_path, chunk_uploaded=None):
"""
This approach is used to attach a file if the file size is between 3 MB and 150 MB, otherwise
if a file that's smaller than 3 MB, then add_file_attachment method is utilized
:param str file_path:
:param ()->None chunk_uploaded: Upload action
"""
max_upload_chunk = 1000000 * 3
file_size = os.stat(file_path).st_size
if file_size > max_upload_chunk:
def _message_loaded():
self.attachments.resumable_upload(
file_path, max_upload_chunk, chunk_uploaded
)
self.ensure_property("id", _message_loaded)
else:
with open(file_path, "rb") as file_object:
content = file_object.read()
self.attachments.add_file(
os.path.basename(file_object.name), content.decode("utf-8")
)
return self
def send(self):
"""
Send a message in the draft folder. The draft message can be a new message draft, reply draft, reply-all draft,
or a forward draft. The message is then saved in the Sent Items folder.
"""
qry = ServiceOperationQuery(self, "send")
self.context.add_query(qry)
return self
def reply(self, comment=None):
"""Reply to the sender of a message by specifying a comment and using the Reply method. The message is then
saved in the Sent Items folder.
:param str comment: A comment to include. Can be an empty string.
"""
message = Message(self.context)
payload = {"message": message, "comment": comment}
qry = ServiceOperationQuery(self, "reply", None, payload)
self.context.add_query(qry)
return message
def reply_all(self):
"""Reply to all recipients of a message. The message is then saved in the Sent Items folder."""
qry = ServiceOperationQuery(self, "replyAll")
self.context.add_query(qry)
return self
def create_reply(self, comment=None):
"""
Create a draft to reply to the sender of a message in either JSON or MIME format.
:param str comment:
"""
return_type = Message(self.context)
payload = {"comment": comment}
qry = ServiceOperationQuery(
self, "createReply", None, payload, None, return_type
)
self.context.add_query(qry)
return self
def create_reply_all(self):
"""
Create a draft to reply to the sender and all the recipients of the specified message.
You can then update the draft to add reply content to the body or change other message properties, or,
simply send the draft.
"""
qry = ServiceOperationQuery(self, "createReplyAll")
self.context.add_query(qry)
return self
def move(self, destination):
"""
Move a message to another folder within the specified user's mailbox.
This creates a new copy of the message in the destination folder and removes the original message.
:param str or MailFolder destination: The destination folder ID, or a well-known folder name.
For a list of supported well-known folder names, see mailFolder resource type.
"""
from office365.outlook.mail.folders.folder import MailFolder
def _move(destination_id):
# type: (str) -> None
payload = {"DestinationId": destination_id}
qry = ServiceOperationQuery(self, "move", None, payload, None, None)
self.context.add_query(qry)
if isinstance(destination, MailFolder):
def _loaded():
_move(destination.id)
destination.ensure_property("id", _loaded)
else:
_move(destination)
return self
def forward(self, to_recipients, comment=""):
"""
Forward a message. The message is saved in the Sent Items folder.
:param list[str] to_recipients: The list of recipients.
:param str comment: A comment to include. Can be an empty string.
"""
payload = {
"toRecipients": ClientValueCollection(
Recipient, [Recipient.from_email(v) for v in to_recipients]
),
"comment": comment,
}
qry = ServiceOperationQuery(self, "forward", None, payload)
self.context.add_query(qry)
return self
@property
def has_attachments(self):
# type: () -> Optional[bool]
"""
Indicates whether the message has attachments. This property doesn't include inline attachments,
so if a message contains only inline attachments, this property is false. To verify the existence
of inline attachments, parse the body property to look for a src attribute,
such as <IMG src="cid:image001.jpg@01D26CD8.6C05F070">.
"""
return self.properties.get("hasAttachments", None)
@property
def attachments(self):
# type: () -> AttachmentCollection
"""The fileAttachment and itemAttachment attachments for the message."""
self._persist_changes("attachments")
return self.properties.setdefault(
"attachments",
AttachmentCollection(
self.context, ResourcePath("attachments", self.resource_path)
),
)
@property
def extensions(self):
# type: () -> EntityCollection[Extension]
"""The collection of open extensions defined for the message. Nullable."""
return self.properties.get(
"extensions",
EntityCollection(
self.context, Extension, ResourcePath("extensions", self.resource_path)
),
)
@property
def body(self):
"""The body of the message. It can be in HTML or text format."""
return self.properties.setdefault("body", ItemBody())
@body.setter
def body(self, value):
# type: (str|ItemBody) -> None
"""Sets the body of the message. It can be in HTML or text format."""
if not isinstance(value, ItemBody):
value = ItemBody(value)
self.set_property("body", value)
@property
def body_preview(self):
# type: () -> Optional[str]
"""The first 255 characters of the message body. It is in text format."""
return self.properties.get("bodyPreview", None)
@property
def conversation_id(self):
# type: () -> Optional[str]
"""The ID of the conversation the email belongs to."""
return self.properties.get("conversationId", None)
@property
def conversation_index(self):
# type: () -> Optional[str]
"""Indicates the position of the message within the conversation."""
return self.properties.get("conversationIndex", None)
@property
def flag(self):
"""
The flag value that indicates the status, start date, due date, or completion date for the message.
"""
return self.properties.get("flag", FollowupFlag())
@property
def sent_from(self):
"""
The owner of the mailbox from which the message is sent. In most cases, this value is the same as the sender
property, except for sharing or delegation scenarios. The value must correspond to the actual mailbox used.
Find out more about setting the from and sender properties of a message.
"""
return self.properties.get("from", Recipient())
@property
def importance(self):
# type: () -> Optional[str]
"""The importance of the message."""
return self.properties.get("importance", None)
@property
def inference_classification(self):
# type: () -> Optional[str]
"""
The classification of the message for the user, based on inferred relevance or importance,
or on an explicit override. The possible values are: focused or other.
"""
return self.properties.get("inferenceClassification", None)
@property
def internet_message_headers(self):
# type: () -> ClientValueCollection[InternetMessageHeader]
"""
A collection of message headers defined by RFC5322. The set includes message headers indicating the network
path taken by a message from the sender to the recipient. It can also contain custom message headers that
hold app data for the message.
"""
return self.properties.get(
"internetMessageHeaders", ClientValueCollection(InternetMessageHeader)
)
@property
def internet_message_id(self):
# type: () -> Optional[str]
"""The message ID in the format specified by RFC2822"""
return self.properties.get("internetMessageId", None)
@property
def is_delivery_receipt_requested(self):
# type: () -> Optional[bool]
"""
Indicates whether a read receipt is requested for the message.
"""
return self.properties.get("isDeliveryReceiptRequested", None)
@property
def is_draft(self):
# type: () -> Optional[bool]
"""
Indicates whether the message is a draft. A message is a draft if it hasn't been sent yet.
"""
return self.properties.get("isDraft", None)
@property
def is_read(self):
# type: () -> Optional[bool]
"""Indicates whether the message has been read."""
return self.properties.get("isRead", None)
@property
def is_read_receipt_requested(self):
# type: () -> Optional[bool]
"""
Indicates whether a read receipt is requested for the message.
"""
return self.properties.get("isReadReceiptRequested", None)
@property
def received_datetime(self):
"""The date and time the message was received."""
return self.properties.get("receivedDateTime", datetime.min)
@property
def sent_datetime(self):
"""The date and time the message was sent."""
return self.properties.get("sentDateTime", datetime.min)
@property
def subject(self):
# type: () -> Optional[str]
"""
The subject of the message.
"""
return self.properties.get("subject", None)
@subject.setter
def subject(self, value):
# type: (str) -> None
"""Sets the subject of the message."""
self.set_property("subject", value)
@property
def to_recipients(self):
"""The To: recipients for the message."""
self._persist_changes("toRecipients")
return self.properties.setdefault(
"toRecipients", ClientValueCollection(Recipient)
)
@property
def bcc_recipients(self):
"""The BCC: recipients for the message."""
self._persist_changes("bccRecipients")
return self.properties.setdefault(
"bccRecipients", ClientValueCollection(Recipient)
)
@property
def cc_recipients(self):
"""The CC: recipients for the message."""
self._persist_changes("ccRecipients")
return self.properties.setdefault(
"ccRecipients", ClientValueCollection(Recipient)
)
@property
def sender(self):
"""The account that is actually used to generate the message. In most cases, this value is the same as the
from property. You can set this property to a different value when sending a message from a shared mailbox,
for a shared calendar, or as a delegate. In any case, the value must correspond to the actual mailbox used.
Find out more about setting the from and sender properties of a message."""
return self.properties.get("sender", Recipient())
@property
def parent_folder_id(self):
# type: () -> Optional[str]
"""The unique identifier for the message's parent mailFolder."""
return self.properties.get("parentFolderId", None)
@property
def web_link(self):
# type: () -> Optional[str]
"""
The URL to open the message in Outlook on the web.
You can append an ispopout argument to the end of the URL to change how the message is displayed.
If ispopout is not present or if it is set to 1, then the message is shown in a popout window.
If ispopout is set to 0, then the browser will show the message in the Outlook on the web review pane.
The message will open in the browser if you are logged in to your mailbox via Outlook on the web.
You will be prompted to login if you are not already logged in with the browser.
This URL cannot be accessed from within an iFrame.
"""
return self.properties.get("webLink", None)
@property
def multi_value_extended_properties(self):
# type: () -> EntityCollection[MultiValueLegacyExtendedProperty]
"""The collection of multi-value extended properties defined for the event."""
return self.properties.get(
"multiValueExtendedProperties",
EntityCollection(
self.context,
MultiValueLegacyExtendedProperty,
ResourcePath("multiValueExtendedProperties", self.resource_path),
),
)
@property
def single_value_extended_properties(self):
# type: () -> EntityCollection[SingleValueLegacyExtendedProperty]
"""The collection of single-value extended properties defined for the message"""
return self.properties.get(
"singleValueExtendedProperties",
EntityCollection(
self.context,
SingleValueLegacyExtendedProperty,
ResourcePath("singleValueExtendedProperties", self.resource_path),
),
)
def get_property(self, name, default_value=None):
if default_value is None:
property_type_mapping = {
"toRecipients": self.to_recipients,
"bccRecipients": self.bcc_recipients,
"ccRecipients": self.cc_recipients,
"from": self.sent_from,
"internetMessageHeaders": self.internet_message_headers,
"multiValueExtendedProperties": self.multi_value_extended_properties,
"receivedDateTime": self.received_datetime,
"sentDateTime": self.sent_datetime,
"singleValueExtendedProperties": self.single_value_extended_properties,
}
default_value = property_type_mapping.get(name, None)
return super(Message, self).get_property(name, default_value)
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
bases |
OutlookItem | - |
Parameter Details
context: The client context object that manages API communication with Microsoft Graph. This is inherited from the OutlookItem base class and is required for all API operations. It handles authentication, request queuing, and execution.
Return Value
The Message class constructor returns a Message instance. Most methods return 'self' (the Message instance) to enable method chaining. Some methods return specific types: get_content() returns ClientResult[AnyStr] containing MIME content, create_forward() and create_reply() return new Message instances representing draft messages, and reply() returns a Message instance for the reply.
Class Interface
Methods
add_extended_property(name: str, value: str) -> Self
Purpose: Creates a single-value extended property for the message with a custom name and value
Parameters:
name: The name of the extended propertyvalue: The string value to store in the extended property
Returns: The Message instance (self) for method chaining
create_forward(to_recipients=None, message=None, comment=None) -> Self
Purpose: Creates a draft message to forward the current message in JSON or MIME format
Parameters:
to_recipients: Optional list of Recipient objects to forward the message tomessage: Optional Message object with additional contentcomment: Optional comment string to include in the forward
Returns: The Message instance (self) for method chaining
download(file_object: IO) -> Self
Purpose: Downloads the MIME content of the message into a file object
Parameters:
file_object: A file-like object opened in binary write mode to receive the MIME content
Returns: The Message instance (self) for method chaining
get_content() -> ClientResult[AnyStr]
Purpose: Retrieves the MIME content of the message as a ClientResult object
Returns: ClientResult containing the MIME content as a string or bytes
add_file_attachment(name, content=None, content_type=None, base64_content=None) -> Self
Purpose: Attaches a file to the message (for files under 3MB)
Parameters:
name: The display name of the attachmentcontent: Optional string content of the filecontent_type: Optional MIME type of the attachmentbase64_content: Optional base64-encoded string content of the file
Returns: The Message instance (self) for method chaining
upload_attachment(file_path, chunk_uploaded=None) -> Self
Purpose: Uploads a file attachment using resumable upload for files between 3MB and 150MB, or regular upload for smaller files
Parameters:
file_path: Path to the file to uploadchunk_uploaded: Optional callback function called after each chunk is uploaded
Returns: The Message instance (self) for method chaining
send() -> Self
Purpose: Sends the message from the draft folder and saves it to Sent Items
Returns: The Message instance (self) for method chaining
reply(comment=None) -> Message
Purpose: Replies to the sender of the message with an optional comment and saves to Sent Items
Parameters:
comment: Optional comment string to include in the reply
Returns: A new Message instance representing the reply
reply_all() -> Self
Purpose: Replies to all recipients of the message and saves to Sent Items
Returns: The Message instance (self) for method chaining
create_reply(comment=None) -> Self
Purpose: Creates a draft reply message without sending it
Parameters:
comment: Optional comment string to include in the reply draft
Returns: The Message instance (self) for method chaining
create_reply_all() -> Self
Purpose: Creates a draft reply-all message without sending it
Returns: The Message instance (self) for method chaining
move(destination) -> Self
Purpose: Moves the message to another folder, creating a copy in the destination and removing the original
Parameters:
destination: Either a string folder ID, well-known folder name, or MailFolder object
Returns: The Message instance (self) for method chaining
forward(to_recipients, comment='') -> Self
Purpose: Forwards the message to specified recipients and saves to Sent Items
Parameters:
to_recipients: List of email address strings to forward the message tocomment: Optional comment string to include in the forward
Returns: The Message instance (self) for method chaining
has_attachments -> Optional[bool]
property
Purpose: Indicates whether the message has attachments (excluding inline attachments)
Returns: Boolean indicating presence of attachments, or None if not loaded
attachments -> AttachmentCollection
property
Purpose: Provides access to the collection of file and item attachments for the message
Returns: AttachmentCollection object for managing attachments
extensions -> EntityCollection[Extension]
property
Purpose: Provides access to the collection of open extensions defined for the message
Returns: EntityCollection of Extension objects
body -> ItemBody
property
Purpose: Gets or sets the body content of the message in HTML or text format
Returns: ItemBody object containing the message body
body_preview -> Optional[str]
property
Purpose: Gets the first 255 characters of the message body in text format
Returns: String preview of the body, or None if not loaded
conversation_id -> Optional[str]
property
Purpose: Gets the ID of the conversation the email belongs to
Returns: String conversation ID, or None if not loaded
conversation_index -> Optional[str]
property
Purpose: Gets the position of the message within the conversation
Returns: String conversation index, or None if not loaded
flag -> FollowupFlag
property
Purpose: Gets the flag value indicating status, start date, due date, or completion date
Returns: FollowupFlag object with flag information
sent_from -> Recipient
property
Purpose: Gets the owner of the mailbox from which the message is sent
Returns: Recipient object representing the sender
importance -> Optional[str]
property
Purpose: Gets the importance level of the message
Returns: String importance value (e.g., 'low', 'normal', 'high'), or None if not loaded
inference_classification -> Optional[str]
property
Purpose: Gets the classification of the message based on inferred relevance or importance
Returns: String classification ('focused' or 'other'), or None if not loaded
internet_message_headers -> ClientValueCollection[InternetMessageHeader]
property
Purpose: Gets the collection of RFC5322 message headers
Returns: ClientValueCollection of InternetMessageHeader objects
internet_message_id -> Optional[str]
property
Purpose: Gets the message ID in RFC2822 format
Returns: String message ID, or None if not loaded
is_delivery_receipt_requested -> Optional[bool]
property
Purpose: Indicates whether a delivery receipt is requested for the message
Returns: Boolean indicating delivery receipt request status, or None if not loaded
is_draft -> Optional[bool]
property
Purpose: Indicates whether the message is a draft that hasn't been sent yet
Returns: Boolean indicating draft status, or None if not loaded
is_read -> Optional[bool]
property
Purpose: Indicates whether the message has been read
Returns: Boolean indicating read status, or None if not loaded
is_read_receipt_requested -> Optional[bool]
property
Purpose: Indicates whether a read receipt is requested for the message
Returns: Boolean indicating read receipt request status, or None if not loaded
received_datetime -> datetime
property
Purpose: Gets the date and time the message was received
Returns: datetime object representing when the message was received, or datetime.min if not loaded
sent_datetime -> datetime
property
Purpose: Gets the date and time the message was sent
Returns: datetime object representing when the message was sent, or datetime.min if not loaded
subject -> Optional[str]
property
Purpose: Gets or sets the subject of the message
Returns: String subject line, or None if not loaded
to_recipients -> ClientValueCollection[Recipient]
property
Purpose: Gets the collection of To: recipients for the message
Returns: ClientValueCollection of Recipient objects
bcc_recipients -> ClientValueCollection[Recipient]
property
Purpose: Gets the collection of BCC: recipients for the message
Returns: ClientValueCollection of Recipient objects
cc_recipients -> ClientValueCollection[Recipient]
property
Purpose: Gets the collection of CC: recipients for the message
Returns: ClientValueCollection of Recipient objects
sender -> Recipient
property
Purpose: Gets the account actually used to generate the message
Returns: Recipient object representing the sender
parent_folder_id -> Optional[str]
property
Purpose: Gets the unique identifier for the message's parent mailFolder
Returns: String folder ID, or None if not loaded
web_link -> Optional[str]
property
Purpose: Gets the URL to open the message in Outlook on the web
Returns: String URL, or None if not loaded
multi_value_extended_properties -> EntityCollection[MultiValueLegacyExtendedProperty]
property
Purpose: Gets the collection of multi-value extended properties defined for the message
Returns: EntityCollection of MultiValueLegacyExtendedProperty objects
single_value_extended_properties -> EntityCollection[SingleValueLegacyExtendedProperty]
property
Purpose: Gets the collection of single-value extended properties defined for the message
Returns: EntityCollection of SingleValueLegacyExtendedProperty objects
get_property(name, default_value=None)
Purpose: Retrieves a property value by name with optional default value, providing type-specific defaults for known properties
Parameters:
name: The name of the property to retrievedefault_value: Optional default value to return if property is not set
Returns: The property value or the default value
Attributes
| Name | Type | Description | Scope |
|---|---|---|---|
context |
ClientContext | The client context object managing API communication (inherited from OutlookItem) | instance |
properties |
dict | Dictionary storing the message's properties and their values (inherited from base class) | instance |
resource_path |
ResourcePath | The API resource path for this message instance (inherited from base class) | instance |
Dependencies
office365typingtyping_extensionsuuidosdatetime
Required Imports
from office365.outlook.mail.messages.message import Message
from office365.outlook.mail.recipient import Recipient
from office365.outlook.mail.item_body import ItemBody
from office365.outlook.mail.attachments.collection import AttachmentCollection
Conditional/Optional Imports
These imports are only needed under specific conditions:
from office365.outlook.mail.folders.folder import MailFolder
Condition: only when using the move() method with a MailFolder object instead of a string ID
OptionalUsage Example
from office365.graph_client import GraphClient
from office365.outlook.mail.messages.message import Message
from office365.outlook.mail.recipient import Recipient
from office365.outlook.mail.item_body import ItemBody
# Initialize client with credentials
client = GraphClient.with_token(lambda: 'your_access_token')
# Create a new message
message = Message(client)
message.subject = 'Hello from Python'
message.body = ItemBody('This is the message body')
message.to_recipients.add(Recipient.from_email('recipient@example.com'))
# Add an attachment
message.add_file_attachment('document.txt', 'File content here', 'text/plain')
# Send the message
message.send()
client.execute_query()
# Reply to an existing message
existing_message = client.me.messages.get_by_id('message_id')
existing_message.reply('Thanks for your message!')
client.execute_query()
# Download message content
with open('message.eml', 'wb') as f:
existing_message.download(f)
client.execute_query()
Best Practices
- Always call client.execute_query() after performing operations to actually execute the queued API requests
- Use method chaining for fluent API style (e.g., message.add_file_attachment(...).send())
- For attachments larger than 3MB, use upload_attachment() instead of add_file_attachment() to leverage resumable upload
- Set the body property using ItemBody object for proper HTML/text formatting control
- Use Recipient.from_email() helper to create recipient objects from email addresses
- When moving messages, ensure the destination folder ID is valid or use well-known folder names
- For draft messages, create and modify the message first, then call send() to actually send it
- Use ensure_property() to lazy-load properties before accessing them if they haven't been fetched
- The context object must be properly authenticated before any operations can be performed
- Extended properties require proper GUID generation and type specification
- When downloading MIME content, ensure the file object is opened in binary mode ('wb')
- Recipients collections (to_recipients, cc_recipients, bcc_recipients) automatically persist changes when modified
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
class EventMessage 75.0% similar
-
class MessageCollection 73.9% similar
-
class MailFolder 68.7% similar
-
class MessageRule 67.9% similar
-
class ItemAttachment 66.1% similar