Working with Message Attachments

Parsing and Saving Attachments

Outlook message files may contain one or more attachments. Aspose.Email lets developers loop through the attachments in an MSG file and save them to disk. This topic describes the process. It also describes how to embed an attachment.

Aspose.Email MapiMessage class is used to load an MSG file from disk and exposes the getAttachments() method which references the MapiAttachment object collection associated with the MSG file. The MapiAttachment object further exposes methods that perform actions on the attachment.

To save attachments in an MSG file to disk with the original name and extension:

  1. Create an instance of the MapiMessage class to load an MSG file using the Load() static method.
  2. Call the MapiRecipient class getAttachments() method to get a reference to the collection of MapiAttachment objects associated with the MSG file.
  3. Loop through the MapiAttachmentCollection to display contents regarding each MapiAttachment object through its public methods.
  4. Call the MapiAttachment class save() method to save attachment to the disk.  

Embedding Messages as Attachments

A Microsoft Outlook message can contain other Microsoft Outlook messages in attachments either as regular messages, described above, or embedded messages. The MapiAttachmentCollection provides overloaded members of the add method for creating Outlook messages with both types of attachments. Outlook MSG files embedded in a MSG file contains a PR_ATTACH_METHOD with the value 5.

Reading an Embedded Message from an Attachment

Add MSG Attachments

An Outlook message can contain other Microsoft Outlook messages in attachments, either as regular or as embedded messages. The MapiAttachmentCollection provides overloaded members of the add method to create Outlook messages with both types of attachments:

  • add(String name, byte[] data) — adds a regular attachment from a byte array.
  • add(String name, MapiMessage message) — adds another Outlook message as an embedded message.

The following code snippet shows you how to add both types of attachments to a message:

MapiMessage message = new MapiMessage("from@test.com", "to@test.com", "Subj", "This is a message body");

// Add a regular attachment from a byte array
message.getAttachments().add("note.txt", Files.readAllBytes(Paths.get("note.txt")));

// Add another Outlook message as an embedded message
MapiMessage attachMsg = MapiMessage.load("Message.msg");
message.getAttachments().add("Weekly report.msg", attachMsg);

message.save("WithAttachments_out.msg");

Add Reference Attachments to MapiMessages

The ReferenceAttachmentOptions class simplifies the addition of reference attachments by encapsulating all necessary properties in a single object:

  • sharedLink — a fully qualified shared link to the attachment provided by the web service hosting the file;
  • url — the file location or resource URL;
  • providerName — the name of the reference attachment provider (e.g. Google Drive, Dropbox).
MapiMessage msg = MapiMessage.load("message.msg");

ReferenceAttachmentOptions options = new ReferenceAttachmentOptions(
        "https://drive.google.com/file/d/1HJ-M3F2qq1oRrTZ2GZhUdErJNy2CT3DF/",
        "https://drive.google.com/drive/my-drive",
        "GoogleDrive");

// Add the reference attachment
msg.getAttachments().add("Document.pdf", options);

msg.save("with-reference-attachment.msg");

Check Attachment Type (IsReference)

The MapiAttachment class includes the isReference() method which allows developers to identify reference attachments in a message:

MapiMessage msg = MapiMessage.load("message.msg");

for (MapiAttachment attachment : msg.getAttachments()) {
    if (attachment.isReference()) {
        // Process the reference attachment
        System.out.println("Reference attachment: " + attachment.getLongFileName());
    }
}

Get Nested Mail Message Attachments

Embedded message attachments also appear in the attachment collection of the MapiMessage class. The MapiMessage.fromProperties() static method creates a new message from an embedded attachment. The following code snippet shows you how to get nested mail message attachments and save them to disk:

MapiMessage msg = MapiMessage.load("message.msg");

for (MapiAttachment attachment : msg.getAttachments()) {
    if (attachment.getObjectData() == null) {
        continue;
    }

    // Create a MapiMessage object from the individual attachment
    MapiMessage nested = MapiMessage.fromProperties(attachment.getObjectData().getProperties());

    // Convert the embedded message to a MailMessage and save it to disk
    MailMessage mailMessage = nested.toMailMessage(new MailConversionOptions());
    mailMessage.save("NestedMailMessageAttachments_out.eml", SaveOptions.getDefaultEml());
}

Remove Attachments

Aspose.Email provides the functionality to remove attachments from Microsoft Outlook message (.msg) files. Call the static removeAttachments() method, which takes the path of the message file as a parameter:

MapiMessage.removeAttachments("AttachmentsToRemove_out.msg");

You can also call the static destroyAttachments() method. It works faster than removeAttachments(), because the latter parses the message file:

MapiMessage.destroyAttachments("AttachmentsToDestroy_out.msg");

Attachments MSG Insertion and Replacement

Aspose.Email API provides the capability to insert attachments at specific index in the parent message. It also provides the facility to replace contents of an attachment with another message attachment.

Insert MSG Attachment at Specific Location

Aspose.Email API provides the capability to insert an MSG attachment to a parent MSG using the MapiAttachmentCollection.Insert() method.

Replace Embedded MSG Attachment Contents

This can be used to replace embedded attachment contents with the new ones using the Replace method. However, it can not be used to insert attachment with PR_ATTACH_NUM = 4(for example) in the collection with collection.Count = 2.

Save Attachments from Digitally Signed Message

Aspose.Email API provides the capability to get or set a value indicating whether clear-signed message will be decoded. 

Rename an Attachment in a MapiMessage

Aspose.Email makes it possible to edit the DisplayName property value in MapiMessage attachments.

The following code sample demonstrates how to update the display names of the first and second attachments within the loaded Mapi message:

MapiMessage msg = MapiMessage.load(fileName);
msg.getAttachments().get_Item(0).setDisplayName("New display name 1");
msg.getAttachments().get_Item(1).setDisplayName("New display name 2");

Check if an Attachment is Inline or Regular

The difference between inline and regular attachments is how they are presented within an email. Inline attachments are embedded within the body of the email and can be viewed without having to open a separate file or download anything. Regular attachments, on the other hand, are separate files that are attached to the email but are not displayed directly within the body of the message and need to be downloaded and opened externally. The MapiAttachment.IsInline property of the MapiAttachment class gets a value indicating whether the attachment is inline or regular.

The following code sample loads an email message from a file and then retrieves information about the attachments, specifically printing the display name of each attachment and whether it is inline within the message or not:

MapiMessage message = MapiMessage.load("fileName");

for (MapiAttachment attach : message.getAttachments()) {
    System.out.println(attach.getDisplayName() + ": " + attach.isInline());
}

Extract Embedded OLE Objects from oledata.mso

Sometimes embedded OLE data is represented as an oledata.mso attachment in a MapiAttachment and needs to be extracted manually. These oledata.mso files are in the Microsoft Compound Document File (MCDF) format, and support for such files is beyond the scope of Aspose.Email. However, Aspose.Email provides the InlineAttachmentExtractor class to enumerate the MSO packages contained in the binary data of oledata.mso, which can then be passed to a compound-file reading library (for example Apache POI POIFS) for content extraction.

When the message body type is HTML (not RTF) and there are OLE objects in the message, the MapiPropertyTag.PR_ATTACH_DATA_OBJ property is absent. In this case, the information about the OLE objects is contained in oledata.mso.

The code below enumerates the MSO packages and writes each of them to a separate file, ready to be opened with a compound-file reader:

MapiMessage msg = MapiMessage.load("double.msg");

for (MapiAttachment mapiAttachment : msg.getAttachments()) {
    if (!"oledata.mso".equals(mapiAttachment.getLongFileName())) {
        continue;
    }

    com.aspose.email.system.collections.generic.IGenericDictionary<String, byte[]> oledata =
            InlineAttachmentExtractor.enumerateMsoPackage(new ByteArrayInputStream(mapiAttachment.getBinaryData()));

    int index = 0;
    for (com.aspose.email.system.collections.generic.KeyValuePair<String, byte[]> oleItem : oledata) {
        // Each value is a compound file - read its CONTENTS stream with an MCDF library,
        // or store it as is for further processing
        Files.write(Paths.get(index + ".mso"), oleItem.getValue());
        index++;
    }
}