Loading, Saving and Converting Emails

Detecting Email File Formats

Aspose.Email API provides the capability to detect file format of the provided message file. The DetectFileFormat method of FileFormatUtil class can be used to achieve this. The following classes and methods can be used to detect the loaded file format:

The following code snippet shows you how to detect file formats:

from aspose.email.tools import FileFormatUtil

# Detect file format and get the detected load format
info = FileFormatUtil.detect_file_format(data_dir + "message.msg")
print("The message format is: " + str(info.file_format_type))

Loading a Message with Load Options

The following code snippet shows you how to load a message with load options.

from aspose.email import MailMessage, EmlLoadOptions, HtmlLoadOptions, MhtmlLoadOptions, MsgLoadOptions

# Load Eml, html, mhtml, msg, and dat files
mail_message = MailMessage.load(data_dir + "message.eml", EmlLoadOptions())
MailMessage.load(data_dir + "description.html", HtmlLoadOptions())
MailMessage.load(data_dir + "message.mhtml", MhtmlLoadOptions())
MailMessage.load(data_dir + "message.msg", MsgLoadOptions())

# Loading with custom options
eml_load_options = EmlLoadOptions()
eml_load_options.preferred_text_encoding = "utf-8"
eml_load_options.preserve_tnef_attachments = True

MailMessage.load(data_dir + "description.html", eml_load_options)

html_load_options = HtmlLoadOptions()
html_load_options.preferred_text_encoding = "utf-8"
html_load_options.should_add_plain_text_view = True
html_load_options.path_to_resources = data_dir

MailMessage.load(data_dir + "description.html", html_load_options)

Preserving Embedded Message Format during Loading

from aspose.email import MailMessage, EmlLoadOptions, HtmlLoadOptions, MhtmlLoadOptions, MsgLoadOptions
from aspose.email.tools import FileFormatUtil

eml_load_options = EmlLoadOptions()
eml_load_options.preserve_embedded_message_format = True

mail = MailMessage.load(data_dir + "message.eml", eml_load_options)

file_format = FileFormatUtil.detect_file_format(mail.attachments[0].content_stream).file_format_type

print("Embedded message file format: " + str(file_format))

Loading an EMLX File

Apple Mail stores its messages in the EMLX format. Use the EmlxLoadOptions class to control how such a file is loaded. It offers the same options as EmlLoadOptions does — encoding preference, embedded message format preservation and signature removal:

import aspose.email as ae

# Instantiate EmlxLoadOptions
load_options = ae.EmlxLoadOptions()
load_options.preferred_text_encoding = "utf-8"
load_options.preserve_embedded_message_format = True
load_options.remove_signature = True

# Load the EMLX file
emlx = ae.MailMessage.load(data_dir + "message.emlx", load_options)
print(emlx.subject)

Loading a Message with or without a Signature

Signature preservation is the default behavior when a message is loaded. To remove the signature while loading, set the remove_signature property of the load options to True:

import aspose.email as ae

options = ae.EmlLoadOptions()
options.remove_signature = True

msg = ae.MailMessage.load(data_dir + "signed.eml", options)
print("Is signed: " + str(msg.is_signed))

Saving and Converting Emails

Aspose.Email makes it easy to convert any message type to another format. To demonstrate this feature, the code in this article loads three types of messages from disk and saves them back in other formats. The base class SaveOptions and the classes EmlSaveOptions, MsgSaveOptions, MhtSaveOptions, HtmlSaveOptions can be used for additional settings when saving messages to other formats. The article shows how to use these classes to save a sample email as:

  • EML format.
  • Outlook MSG.
  • MHTML format.
  • HTML format.

Saving as EML

The following code snippet shows you how to load an EML message and save it to the disc in the same format.

from aspose.email import MailMessage, SaveOptions

# Initialize and Load an existing EML file by specifying the MessageFormat
mail_message = MailMessage.load(data_dir + "message.eml")

mail_message.save(data_dir + "LoadAndSaveFileAsEML_out.eml", SaveOptions.default_eml)

Preserving Boundaries in EML Files

The following code snippet shows you how to load an EML file and save it in the same format preserving the original boundaries.

from aspose.email import MailMessage, EmlSaveOptions, MailMessageSaveType

mail_message = MailMessage.load(data_dir + "message.eml")

# Save as eml with preserved original boundaries
eml_save_options = EmlSaveOptions(MailMessageSaveType.eml_format)

mail_message.save(data_dir + "PreserveOriginalBoundaries_out.eml", eml_save_options)

Customize MIME Boundary Strings

Aspose.Email for .NET allows you to configure the boundary template used in MIME messages. This is achieved through the boundaries_template property of the EmlSaveOptions class.

By setting a custom template, you can define how MIME boundaries are generated. The {#} wildcard in the template will be replaced with an incremental boundary number, enabling dynamic and readable boundary strings.

If boundaries_template is not set (default is None), the library uses its internal boundary format.

The following code sample shows how to customize the MIME boundary strings when saving an email message to the .eml format:

import aspose.email as ae

# Create a sample MailMessage
message = ae.MailMessage()
message.subject = "Custom MIME Boundary"
message.body = "This message uses a custom MIME boundary template."
message.to.append(ae.MailAddress("recipient@example.com"))

# Configure save options with a custom boundary template
save_options = ae.EmlSaveOptions(ae.MailMessageSaveType.eml_format)
save_options.boundaries_template = "boundary--{#}"

# Save the message to .eml with custom boundaries
message.save("Custom_Boundary_Message.eml", save_options)

Here is an example of the message structure with custom boundares saved using the code shown above:

From: sender@example.com  
To: recipient@example.com  
Subject: Custom_Boundary_Message  
Date: Fri, 27 Dec 2024 12:00:00 +0000
Content-Type: multipart/mixed;
 boundary="boundary--1"

This is a multi-part message in MIME format.

--boundary--1
Content-Type: multipart/alternative; boundary="boundary--2"


--boundary--2
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable

Content-Type: text/plain; charset="us-ascii"

This is the plain text content of the email.


--boundary--2
Content-Type: text/html; charset="windows-1251"
Content-Transfer-Encoding: quoted-printable

<html>
  <body>
    <p>This is the <b>HTML</b> content of the email.</p>
  </body>
</html>

--boundary--2--

--boundary--1
Content-Type: application/octet-stream; name="report-2023-08.xlsx"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="report-2023-08.xlsx"

UEsDBBQABgAIAAAAIQBi7...

--boundary--1--

Preserving TNEF Attachments in EML Files

The following code snippet shows you how to save an EML file preserving TNEF attachments.

from aspose.email import MailMessage, EmlSaveOptions, MailMessageSaveType, FileCompatibilityMode

mail_message = MailMessage.load(data_dir + "message.eml")

# Save as eml with preserved attachment
eml_save_options = EmlSaveOptions(MailMessageSaveType.eml_format)
eml_save_options.file_compatibility_mode = FileCompatibilityMode.PRESERVE_TNEF_ATTACHMENTS

mail_message.save(data_dir + "PreserveTNEFAttachment_out.eml", eml_save_options)

Saving as MSG

The following code snippet shows you how to load an EML message and convert it to MSG using the appropriate option from SaveOptions.

from aspose.email import MailMessage, SaveOptions, MailMessageSaveType, FileCompatibilityMode

# Initialize and Load an existing EML file by specifying the MessageFormat
eml = MailMessage.load(data_dir + "message.eml")

# Save the Email message to disk in ASCII format and Unicode format
eml.save(data_dir + "AnEmail_out.msg", SaveOptions.default_msg_unicode)

Preserving Dates in MSG Files

The MsgSaveOptions class allows you to save the source message as an Outlook Message file (MSG) preserving dates. The following code snippet shows you how to save an EML file as MSG and preserve dates.

from aspose.email import MailMessage, MsgSaveOptions, MailMessageSaveType, FileCompatibilityMode

# Initialize and Load an existing EML file by specifying the MessageFormat
eml = MailMessage.load(data_dir + "message.eml")

# Save as msg with preserved dates
msg_save_options = MsgSaveOptions(MailMessageSaveType.outlook_message_format_unicode)
msg_save_options.preserve_original_dates = True

eml.save(data_dir + "outTest_out.msg", msg_save_options)

Saving as MHTML

Different options of MHTML can be used to obtain the desired results. The following code snippet shows you how to load an EML message into MailMessage and convert it to MHTML.

from aspose.email import MailMessage, SaveOptions, MailMessageSaveType, FileCompatibilityMode

# Initialize and Load an existing EML file by specifying the MessageFormat
eml = MailMessage.load(data_dir + "message.eml")

eml.save(data_dir + "AnEmail_out.mhtml", SaveOptions.default_mhtml)

Custom MHTML Conversion Settings

The MhtSaveOptions class provides additional options for saving email messages to MHTML format. The enumerator MhtFormatOptions makes it possible to write additional email information to the output MHTML. The following additional fields can be written:

  • NONE - No specific settings are specified.
  • WRITE_HEADER - Indicates that header information should be written.
  • WRITE_OUTLINE_ATTACHMENTS - Indicates that outline attachments should be written.
  • WRITE_COMPLETE_EMAIL_ADDRESS - Indicates that complete e-mail address should be written in all email headers.
  • NO_ENCODE_CHARACTERS - Indicates that no transfer encoding of characters should be used.
  • HIDE_EXTRA_PRINT_HEADER - Indicates that PageHeader will be unvisible.
  • WRITE_COMPLETE_TO_EMAIL_ADDRESS - Indicates that complete e-mail address should be written in ‘To’ header.
  • WRITE_COMPLETE_FROM_EMAIL_ADDRESS - Indicates that complete e-mail address should be written in ‘From’ header.
  • WRITE_COMPLETE_CC_EMAIL_ADDRESS - Indicates that complete e-mail address should be written in ‘Cc’ header.
  • WRITE_COMPLETE_BCC_EMAIL_ADDRESS - Indicates that complete e-mail address should be written in ‘Bcc’ header.
  • RENDER_CALENDAR_EVENT - Indicates that text from calendar event should be written in output mhtml.
  • SKIP_BYTE_ORDER_MARK_IN_BODY - Indicates that Byte Order Mark (BOM) bytes should be written to body.
  • RENDER_V_CARD_INFO - Indicates that text from VCard AlternativeView should be written in output mhtml.
  • DISPLAY_AS_OUTLOOK - Indicates that From header will be displayed as in Outlook.
  • RENDER_TASK_FIELDS - Indicates that the specific Task fields should be written in output mhtml.

The following code snippet shows you how to convert an EML file to MHTML with optional settings.

from aspose.email import MailMessage, MhtSaveOptions, MhtFormatOptions, MailMessageSaveType, FileCompatibilityMode

# Load an existing EML file
eml = MailMessage.load(data_dir + "message.eml")

# Save as mht with header
mht_save_options = MhtSaveOptions()

# Specify formatting options required
# Here we are specifying to write header information to output without writing extra print header
# and the output headers should be displayed as the original headers in the message
mht_save_options.mht_format_options = MhtFormatOptions.WRITE_HEADER | MhtFormatOptions.HIDE_EXTRA_PRINT_HEADER | MhtFormatOptions.DISPLAY_AS_OUTLOOK

# Check the body encoding for validity.
mht_save_options.check_body_content_encoding = True

eml.save(data_dir + "outMessage_out.mht", mht_save_options)

Including Calendar Events in MHTML Conversion

The MhtFormatOptions.RenderCalendarEvent renders the Calendar events to the output MHTML. The following code snippet shows you how to render calendar events while converting to MHTML:

from aspose.email import MailMessage, MhtSaveOptions, MhtFormatOptions, MhtTemplateName, MailMessageSaveType, FileCompatibilityMode

file_name = "message.msg"

# Load the MSG file
msg = MailMessage.load(data_dir + file_name)

# Create MHT save options
options = MhtSaveOptions()
options.mht_format_options = MhtFormatOptions.WRITE_HEADER | MhtFormatOptions.RENDER_CALENDAR_EVENT

# Save the message as MHTML
msg.save(data_dir + "Meeting with Recurring Occurrences.mhtml", options)

Exporting Email to MHT without Inline Images

from aspose.email import MailMessage, MhtSaveOptions, MhtFormatOptions, MhtTemplateName, MailMessageSaveType, FileCompatibilityMode

# Load the EML file
eml = MailMessage.load(data_dir + "message.eml")

# Create MHT save options
mht_save_options = MhtSaveOptions()
mht_save_options.skip_inline_images = True

# Save the message as MHTML without inline images
eml.save(data_dir + "EmlToMhtmlWithoutInlineImages_out.mht", mht_save_options)

Exporting Email to MHT with Custom Time Zone

MailMessage class provides the TimeZoneOffset property to set customized time zone while exporting to MHT. The following code snippet shows you how to export an email to MHT with customized time zone:

from aspose.email import MailMessage, MhtSaveOptions, MhtFormatOptions, MhtTemplateName, MailMessageSaveType, FileCompatibilityMode
from datetime import timedelta

# Load the EML file
eml = MailMessage.load(data_dir + "message.eml")

# Set the local time for message date
eml.time_zone_offset = timedelta(hours=-8)

# The dates will be rendered by the local system time zone
mht_save_options = MhtSaveOptions()
mht_save_options.mht_format_options = MhtFormatOptions.WRITE_HEADER
eml.save(data_dir + "ExportEmailToMHTWithCustomTimezone_out.mhtml", mht_save_options)

Adjusting Fonts in the MHTML Output

The css_styles property of the MhtSaveOptions class holds the style sheet written into the output file. Insert your own rules before the closing </style> tag to override the default appearance:

import aspose.email as ae

eml = ae.MailMessage.load(data_dir + "message.eml")

options = ae.MhtSaveOptions()
css_insert_pos = options.css_styles.rfind("</style>")
options.css_styles = (options.css_styles[:css_insert_pos]
                      + ".PlainText{ font-family: sans-serif; }"
                      + options.css_styles[css_insert_pos:])

eml.save(data_dir + "message_out.mhtml", options)

Saving as HTML

The HtmlSaveOptions class allows you to export the message body to HTML with the option to control how embedded resources are rendered through the resource_rendering_mode property. The following code snippet shows you how to save a message as HTML; by default the resources are embedded into the HTML (ResourceRenderingMode.EMBED_INTO_HTML), while ResourceRenderingMode.SAVE_TO_FILE writes them as separate files.

from aspose.email import MailMessage, SaveOptions, HtmlSaveOptions, HtmlFormatOptions, ResourceRenderingMode

# Load the EML file
message = MailMessage.load(data_dir + "message.eml")

# Save the Email message as HTML
message.save(data_dir + "SaveAsHTML_out.html", SaveOptions.default_html)

# OR

eml = MailMessage.load(data_dir + "message.eml")
options = HtmlSaveOptions()
options.resource_rendering_mode = ResourceRenderingMode.SAVE_TO_FILE
options.html_format_options = (
    HtmlFormatOptions.WRITE_HEADER
    | HtmlFormatOptions.WRITE_COMPLETE_EMAIL_ADDRESS
)  # save the message headers to output HTML using the formatting options
eml.save(data_dir + "SaveAsHTML1_out.html", options)

Controlling How Resources Are Rendered

The resource_rendering_mode property of the HtmlSaveOptions class defines how the message resources (inline images, for example) are written to the output HTML. It accepts the values of the ResourceRenderingMode enumeration:

  • EMBED_INTO_HTML – embed the resources into the HTML as base64 strings. This is the default value.
  • SAVE_TO_FILE – save the resources to files and insert the path to each file into the src tag.
  • SUBSTITUTE_FROM_FILE – use a custom file as an icon and insert the path to it into the src tag.
  • NONE – do not render the resources in the HTML.

When the resources are saved to files, the use_relative_path_to_resources property controls whether the paths written into the HTML are relative or absolute.

import aspose.email as ae

msg = ae.MailMessage.load(data_dir + "EmailWithAttandEmbedded.eml")

options = ae.HtmlSaveOptions()
options.resource_rendering_mode = ae.ResourceRenderingMode.SAVE_TO_FILE
options.use_relative_path_to_resources = True

msg.save(data_dir + "EmailWithAttandEmbedded.html", options)

Saving as Outlook Template (.OFT)

To save a message as an Outlook template, use the SaveOptions.default_oft options — they carry the outlook_template_format save type. The same result is achieved by creating an MsgSaveOptions object with MailMessageSaveType.outlook_template_format.

The following code snippet shows you how to save a message as an Outlook template (.oft) file:

from aspose.email import MailMessage, SaveOptions

eml = MailMessage("test@from.to", "test@to.to", "template subject", "Template body")

oft_eml_file_name = "EmlAsOft_out.oft"
options = SaveOptions.default_oft

eml.save(data_dir + oft_eml_file_name, options)

Converting EML to MSG (MailMessage to MapiMessage)

To convert a MailMessage object loaded from an EML file to a MapiMessage object, use the MapiConversionOptions class. This conversion is often necessary because the two objects serve different purposes. MapiMessage is specifically designed for compatibility with Microsoft Outlook and Exchange Server, as it adheres to the Messaging Application Programming Interface (MAPI) format. This makes sure that the emails converted to MSG files are fully compatible with Microsoft products and can be opened, modified and managed directly in Outlook.

The conversion is also required when the emails need to be archived, indexed or processed by the storages that require the MAPI format — PST/OST and OLM storages, for example.

  1. Create an instance of MapiConversionOptions and configure its properties.
  2. Convert the MailMessage object to a MapiMessage object with the MapiMessage.from_mail_message() method, passing the configured options.
import aspose.email as ae
from aspose.email.mapi import MapiMessage, MapiConversionOptions, OutlookMessageFormat

eml = ae.MailMessage.load(data_dir + "email.eml", ae.EmlLoadOptions())

# Create an instance of MapiConversionOptions
conversion_options = MapiConversionOptions()
conversion_options.format = OutlookMessageFormat.UNICODE          # use the Unicode format for MSG
conversion_options.preserve_embedded_message_format = True        # preserve the format of the embedded messages
conversion_options.preserve_original_addresses = True             # keep the original email addresses
conversion_options.preserve_original_dates = True                 # preserve the original dates
conversion_options.preserve_empty_dates = False                   # generate new dates if the original ones are empty
conversion_options.remove_signature = False                       # do not remove the signature
conversion_options.use_body_compression = True                    # enable the RTF body compression
conversion_options.forced_rtf_body_for_appointment = False        # disable the forced RTF body for appointments

# Convert MailMessage to MapiMessage
msg = MapiMessage.from_mail_message(eml, conversion_options)
msg.save(data_dir + "converted_out.msg")

Available Properties of MapiConversionOptions

  • ascii_format: returns MapiConversionOptions configured with the ASCII Outlook message format. This option is useful when you need a plain ASCII format conversion.
  • unicode_format: returns MapiConversionOptions configured with the Unicode Outlook message format. Use this option for more comprehensive character support in MSG files.
  • forced_rtf_body_for_appointment: when set to True, forces the use of the RTF body for calendar appointments. This is useful if you want to make sure the message is compatible with certain mail clients.
  • format: specifies the output format for the MSG file. It can be set to either OutlookMessageFormat.ASCII or OutlookMessageFormat.UNICODE.
  • preserve_embedded_message_format: determines whether to retain the original EML format of the embedded messages during the conversion. The default is False.
  • preserve_empty_dates: when set to True, retains the original saving and modification dates from the EML. Otherwise, new dates are generated if the original ones are empty.
  • preserve_original_addresses: if set to True, maintains the original email addresses without validation. This is useful when working with the email addresses that might not conform to strict standards but need to be preserved as is. The default is False.
  • preserve_original_dates: makes sure the original sending and receiving dates are kept during the conversion.
  • remove_signature: controls whether the digital signature, if present, is removed from the message during the conversion. The default is False.
  • use_body_compression: enables the RTF body compression if set to True. This helps reduce the size of the MSG file, especially when dealing with large messages with rich formatting.