Cannot get URI from Modern Attachments

SampleFiles.zip (82.5 KB)

Aspose Team,
We use the Aspose Email java package to extract msg from pst files and extract attachments from the extracted msg. Some pst files contain MS Teams messages and those messages may contain modern attachments that contain the URI of the shared link instead of the actual content. If we can get the URI we should be able to download the actual attachments. However, we cannot get the URI with Aspose Email.

Following is the sample code and attached are the sample files. The operating system is Ubuntu 20.04. Java version is 21. Aspose Email java packages is 24.5.

We can check if the attachment contains URI with the Attachment.isUri() method. And we can see the URI in the debugging information in IntelliJ (see below). We can even get the URI with the method attachment.f().a(). But this method is not public and we cannot use it in our program.

Wonder if you can make the method(s) attachment.f().a() public so that we can get URI from modern attachments.

Debugging information of Sample file 0_with_att.msg:

attachment:
result = {ReferenceAttachment@2401}
e = {zay@2402} “Sign in to your account Documents/Versions/100_Versions (1).docx”
f = 0
g = 0
d = null
Attachment.e = null
isUri = true
a = 0
Attachment.f = {ObjectIdentifier@2403}
Attachment.g = null
b = false
c = -1
AttachmentBase.a = {zaqo@2404}
AttachmentBase.d = true

attachment.getName():
result = “100_Versions (1).docx”
value = {byte[21]@2430} [49, 48, 48, 95, 86, 101, 114, 115, 105, 111, 110, 115, 32, 40, 49, 41, 46, 100, 111, 99, 120]
coder = 0
hash = 0
hashIsZero = false

attachment.f().a():
result = “Sign in to your account Documents/Versions/100_Versions (1).docx”
value = {byte[99]@2411} [104, 116, 116, 112, 115, 58, 47, 47, 101, 112, 105, 113, 115, 97, 110, 100, 98, 111, 120, 46, 115, 104, 97, 114, 101, 112, 111, 105, 110, 116, 46, 99, 111, 109, 47, 115, 105, 116, 101, 115, 47, 85, 71, 45, 69, 67, 67, 84, 101, 115, 116, 47, 83, 104, 97, 114, 101, 100, 32, 68, 111, 99, 117, 109, 101, 110, 116, 115, 47, 86, 101, 114, 115, 105, 111, 110, 115, 47, 49, 48, 48, 95, 86, 101, 114, 115, 105, 111, 110, 115, 32, 40, 49, 41, 46, 100, 111, 99, 120]
coder = 0
hash = 0
hashIsZero = false

Sample code:

import com.aspose.email.Attachment;
import com.aspose.email.MailMessage;
import com.aspose.email.MsgLoadOptions;

public class TeamsAttachment_31 {
public static void main(String[] args) {
try {

        String inputMsg = "/home/ubuntu/winshare/00_Sample_Files/Archives/Pst_Teams/UG_ECCTest_extracted_selected/0_with_att.msg";
        String outputDir = "/home/ubuntu/winshare/00_Sample_Files/Archives/Pst_Teams/UG_ECCTest_extracted_selected/outdir/";
        MsgLoadOptions msgLoadOptions = new MsgLoadOptions();
        msgLoadOptions.setPreserveEmbeddedMessageFormat(true);
        MailMessage mailMessage = MailMessage.load(inputMsg, msgLoadOptions);

        for (int i = 0; i < mailMessage.getAttachments().size(); i++) {
            Attachment attachment = mailMessage.getAttachments().get_Item(i);
            if(attachment != null) {
                String outputFile = outputDir + "attachment_" + i;
                attachment.save(outputFile);
                Boolean isUri = attachment.isUri();
                System.out.println("isUri = " + isUri);
            }
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

}

@xyang
We have opened the following new ticket(s) in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.

Issue ID(s): EMAILJAVA-35307

You can obtain Paid Support Services if you need support on a priority basis, along with the direct access to our Paid Support management team.

Hello @xyang,

In case of Uri attachment, you can cast the object to the ReferenceAttachment class to get the Uri property.
However, some issues were found in the current implementation, which have been fixed and will be available in version 24.7.
Version 24.7 will be released in the first days of August.

if (attachment.isUri()) {
    ReferenceAttachment refAttachment = (ReferenceAttachment)attachment;
    System.out.println(refAttachment.getUri().toString());
}

Thank you @sergey.vivsiuk ,

We will try it once 24.7 is available.

I have another question: Is it possible to retrieve MS Teams related properties (such as the team name, team id, channel name etc.) from messages (message class “IPM.SkypeTeams.Message”) with Aspose Email? I can create a new topic is necessary.

Hello @xyang,

To better understand and assist you with retrieving MS Teams-related properties from messages with the message class “IPM.SkypeTeams.Message”, could you please provide an example MSG file? This will help us analyze the structure and determine if these properties can be accessed.

Thank you.

Hello @xyang,

Can you extract all properties of the MAPI message and analyze them for the presence of known team name, team ID, and channel name fields?

MapiMessage msg = MapiMessage.load("0_with_att.msg");
// print all msg properties
for (Object obj : msg.getProperties().getValues())
{
    MapiProperty property = (MapiProperty)obj;
    System.out.println(property.getTag());
    System.out.println(property.getDescriptor());
    System.out.println(property);
    System.out.println("------------------------------------");
}

@sergey.vivsiuk

With the suggested code, I am able to get the Teams related properties. Following is a couple of properties from 0_with_att.msg:

tag: 2149122079

description: Name:‘’:IOpenTypedFacet.SkypeSpaces_ConversationPost_Extension#ThreadId:31:f6e4ba45-c83c-45da-8f38-43bd3fe76d5c

value: 19:0e8853aaaa9c4afbb0cb91340ac20cca@thread.tacv2


tag: 2149187615

description: Name:‘’:IOpenTypedFacet.SkypeSpaces_ConversationPost_Extension#TeamName:31:f6e4ba45-c83c-45da-8f38-43bd3fe76d5c

value: UG-ECC Test


tag: 2149253151

description: Name:‘’:IOpenTypedFacet.SkypeSpaces_ConversationPost_Extension#Topic:31:f6e4ba45-c83c-45da-8f38-43bd3fe76d5c

value: Versions


tag: 2149318687

description: Name:‘’:IOpenTypedFacet.SkypeSpaces_ConversationPost_Extension#ParentMessageId:31:f6e4ba45-c83c-45da-8f38-43bd3fe76d5c

value: 1603408745397

@margarita.samodurova

You can use the 6 msg files in the previously uploaded zip file (Sample.zip) to analyze. Here is the pst file from which the msg files are extracted from.
SamplePst.zip (1.4 MB)

Hello @xyang,

Thank you for providing the files. Our developers will analyze them, and we’ll get back to you with a response.

@xyang ,

Here’s a method you can use to access MAPI properties related to MS Teams:

public final void printTeamProps() {
    MapiMessage msg = MapiMessage.load("0_with_att.msg");

    MapiProperty threadIdProp = getTeamProperty(msg, "ThreadId");
    if (threadIdProp != null) {
        System.out.println("ThreadId: " + threadIdProp.getString());
    }
    MapiProperty teamNameProp = getTeamProperty(msg, "TeamName");
    if (teamNameProp != null) {
        System.out.println("TeamName: " + teamNameProp.getString());
    }
    MapiProperty topicProp = getTeamProperty(msg, "Topic");
    if (topicProp != null) {
        System.out.println("Topic: " + topicProp.getString());
    }
    MapiProperty parentMessageIdProp = getTeamProperty(msg, "ParentMessageId");
    if (parentMessageIdProp != null) {
        System.out.println("ParentMessageId: " + parentMessageIdProp.getString());
    }

}

private MapiProperty getTeamProperty(MapiMessage msg, String name) {
    return msg.getProperty(
            new PidNamePropertyDescriptor(
                    "IOpenTypedFacet.SkypeSpaces_ConversationPost_Extension#" + name,
                    PropertyDataType.String,
                    UUID.fromString("f6e4ba45-c83c-45da-8f38-43bd3fe76d5c")));
}

@sergey.vivsiuk

I tested the suggested methods with sample file 0_with_att.msg. They worked for most of the properties (ThreadId, TeamName, ParentMessageId, SkypeItemId, MessageType, ThreadType, Topic). But they failed for property CreatedDateTime. Note that CreatedDateTime has the following raw data:

    tag: 2149777472

description: Name:‘’:IOpenTypedFacet.SkypeSpaces_ConversationPost_Extension#CreatedDateTime:64:f6e4ba45-c83c-45da-8f38-43bd3fe76d5c
value: 10/22/2020 11:19:05 PM

In addition, I tried to use the following methods to get ContainsExternalParticipants and it failed.

private MapiProperty getTeamProperty2(MapiMessage msg, String name) {
    return msg.getProperty(
            new PidNamePropertyDescriptor(
                    "IOpenTypedFacet.Com_Compliance_ExternalParticipants#" + name,
                    PropertyDataType.String,
                    UUID.fromString("f6e4ba45-c83c-45da-8f38-43bd3fe76d5c")));
}

Note that ContainsExternalParticipants has the following raw data:
tag: 2149974027
description: Name:‘’:IOpenTypedFacet.Com_Compliance_ExternalParticipants#ContainsExternalParticipants:11:f6e4ba45-c83c-45da-8f38-43bd3fe76d5c
value: false

I tried to use the following methods to get LinkId and it succeeded.

private MapiProperty getTeamProperty3(MapiMessage msg, String name) {
    return msg.getProperty(
            new PidNamePropertyDescriptor(
                    "IOpenTypedFacet.Com_Compliance_Callback#" + name,
                    PropertyDataType.String,
                    UUID.fromString("f6e4ba45-c83c-45da-8f38-43bd3fe76d5c")));
}

Note that LinkId has the following raw data:
tag: 2149449759
description: Name:‘’:IOpenTypedFacet.Com_Compliance_Callback#LinkId:31:f6e4ba45-c83c-45da-8f38-43bd3fe76d5c
value: 1603408745397

Seems that the value before “f6e4ba45-c83c-45da-8f38-43bd3fe76d5c” must be 31 in the raw data for PidNamePropertyDescriptor to work. Can you make it accept value rather than 31?

Hello @xyang ,

You can use the code below to get the DateTime property:

public final void printTeamProps() {
    MapiMessage msg = MapiMessage.load("16_with_att.msg");

    MapiProperty threadIdProp = getTeamProperty(msg, "ThreadId");
    if (threadIdProp != null) {
        System.out.println("ThreadId: " + threadIdProp.getString());
    }
    MapiProperty teamNameProp = getTeamProperty(msg, "TeamName");
    if (teamNameProp != null) {
        System.out.println("TeamName: " + teamNameProp.getString());
    }
    MapiProperty topicProp = getTeamProperty(msg, "Topic");
    if (topicProp != null) {
        System.out.println("Topic: " + topicProp.getString());
    }
    MapiProperty parentMessageIdProp = getTeamProperty(msg, "ParentMessageId");
    if (parentMessageIdProp != null) {
        System.out.println("ParentMessageId: " + parentMessageIdProp.getString());
    }
    //  >>> getTeamDateProperty
    MapiProperty сreatedDateTimeProp = getTeamDateProperty(msg, "CreatedDateTime");
    if (сreatedDateTimeProp != null) {
        System.out.println("CreatedDateTime: " + сreatedDateTimeProp.getDateTime());
    }

}

private MapiProperty getTeamProperty(MapiMessage msg, String name) {
    return msg.getProperty(
            new PidNamePropertyDescriptor(
                    "IOpenTypedFacet.SkypeSpaces_ConversationPost_Extension#" + name,
                    // data type :31: string
                    PropertyDataType.String,
                    UUID.fromString("f6e4ba45-c83c-45da-8f38-43bd3fe76d5c")));
}

private MapiProperty getTeamDateProperty(MapiMessage msg, String name) {
    return msg.getProperty(
            new PidNamePropertyDescriptor(
                    "IOpenTypedFacet.SkypeSpaces_ConversationPost_Extension#" + name,
                    // data type :64: time
                    PropertyDataType.Time,
                    UUID.fromString("f6e4ba45-c83c-45da-8f38-43bd3fe76d5c")));
}

@sergey.vivsiuk

CreatedDateTime works with getTeamDateProperty.
Also I made ContainsExternalParticipants work with PropertyDataType.Boolean.

Thanks you very much.

@xyang ,

Thank you for the feedback.

Hello and sorry for jumping in, may I request to have a MS Teams Mapi message .msg sample? Just need to examine, best :slight_smile:

We’re unable to share customer files with external parties due to confidentiality and privacy commitments. Please consider exploring Microsoft’s documentation or other online sources for similar samples.

@sergey.vivsiuk

I tested version 24.7 and the suggested method (see below) works. Thank you very much

if (attachment.isUri()) {
    ReferenceAttachment refAttachment = (ReferenceAttachment)attachment;
    System.out.println(refAttachment.getUri().toString());
}

@xyang,

Thank you for the feedback.
If you have any more questions or need further assistance, feel free to ask.

Hello @sergey.vivsiuk

In your suggested methods for getting Teams properties (see below) there are some hard-coded values like “IOpenTypedFacet.SkypeSpaces_ConversationPost_Extension#” and “f6e4ba45-c83c-45da-8f38-43bd3fe76d5c”.

I wonder if those values are specifical to the sample files that I provided in this topic or they are generic to all Teams messages (from different accounts/business).

Currently we have sample files from only one account and we are not sure if those hard-coded values will work for Teams messages from other accounts/businesses.

private MapiProperty getTeamProperty(MapiMessage msg, String name) {
return msg.getProperty(
new PidNamePropertyDescriptor(
“IOpenTypedFacet.SkypeSpaces_ConversationPost_Extension#” + name,
// data type :31: string
PropertyDataType.String,
UUID.fromString(“f6e4ba45-c83c-45da-8f38-43bd3fe76d5c”)));
}

private MapiProperty getTeamDateProperty(MapiMessage msg, String name) {
return msg.getProperty(
new PidNamePropertyDescriptor(
“IOpenTypedFacet.SkypeSpaces_ConversationPost_Extension#” + name,
// data type :64: time
PropertyDataType.Time,
UUID.fromString(“f6e4ba45-c83c-45da-8f38-43bd3fe76d5c”)));
}

Hello @xyang,

The hard-coded values like “IOpenTypedFacet.SkypeSpaces_ConversationPost_Extension#” and “f6e4ba45-c83c-45da-8f38-43BD3FE76D5C” are specific to the Microsoft Teams message properties defined within the Exchange Web Services (EWS) schema. These values represent the property names and GUIDs used by Microsoft to store metadata related to Teams messages.

In general, these values are part of the underlying EWS infrastructure used to store and retrieve properties. The identifiers for these properties are consistent across all accounts.

Hello @margarita.samodurova,
Thank you for the explanation. You mentioned “The identifiers for these properties are consistent across all accounts.”. Wonder if the identifiers for these properties are consistent across companies. Our client data may come from different companies.