Transport-Neutral Encapsulation Format (TNEF)

TNEF is a format for converting a set of MAPI properties-a MAPI message-into a serial data stream. The TNEF functions are primarily used by transport providers that need to encode MAPI message properties for transmission through a messaging system that does not support those properties directly. For example, an SMTP based transport would use TNEF to encode properties like PR_SENT_REPRESENTING, which do not have direct representations in the structure of an SMTP message.

The TNEF implementation defines several TNEF-specific attributes, each of which correspond to particular MAPI properties. These attributes are used to encode their respective MAPI properties into the TNEF stream. In addition, a special attribute is defined that can be used to encapsulate any MAPI property that does not have a specific attribute corresponding to it. The reason these attributes are defined, instead of simply using a uniform encoding method for all MAPI properties, is to enable backward compatibility with non-MAPI software that is using TNEF such as Microsoft Mail 3.x and its transport providers.

The remainder of this appendix describes the structure and syntax of a TNEF stream, the mapping between MAPI properties and TNEF attributes, and important considerations for certain TNEF attributes.

TNEF Stream Structure

A TNEF stream begins with a 32-bit signature that identifies the stream as a TNEF stream. Following the signature is a 16-bit unsigned integer that is used as a key to cross-reference attachments to their location within the tagged message text. The remainder of the stream is a sequence of TNEF attributes. Message attributes appear first in the TNEF stream, and attachment attributes follow. Attributes belonging to a particular attachment are grouped together, beginning with the attAttachRenddata attribute.

Most of the constant values used in TNEF streams are defined in the tnef.h header file. Notably, TNEF_SIGNATURE, LVL_MESSAGE, LVL_ATTACHMENT, and all the TNEF attribute identifiers are defined in that file. Other constants have the values indicated by their interpretation to a C language compiler. Typically such constants are used to give the sizes of the following item. For example, sizeof(ULONG) in an item's definition indicates that an integer representing the size of the following unsigned long integer should occur in that place in the TNEF stream.

All integers in a TNEF stream are stored in little-endian binary form, but are shown in hexadecimal throughout this appendix. Checksum values are simply 16-bit unsigned integers that are the sum, modulo 65536, of the bytes of data that the checksum applies to. All attribute lengths are unsigned long integers, including any terminating null characters.

The key is a nonzero, 16-bit unsigned integer that signifies the initial value of the attachment reference keys. The attachment reference keys are assigned to each attachment sequentially beginning with the initial value, that is passed to the OpenTnefStream function by the service provider that is using TNEF. The service provider should generate a random initial value for the key to minimize the chance that two messages use the same key.

The TNEF implementation uses attribute identifiers to map attributes to their corresponding MAPI properties. An attribute identifier is a 32-bit unsigned integer made up of two word values. The high-order word is an indication of the data type, such as string or binary, and the low-order word identifies the particular attribute. The data types in the high order word are:
TypeValue
atpTriples0x0000
atpString0x0001
atpText0x0002
atpDate0x0003
atpShort0x0004
atpLong0x0005
atpByte0x0006
atpWord0x0007
atpDword0x0008
atpMax0x0009

The low-order word values for each attribute are defined in the tnef.h header file.

TNEF Stream Syntax

This topic presents a Bakus-Nauer like description of the TNEF stream syntax. In this description, non-terminal elements that have a further definition are in italics. Constants and literal items are in bold. Sequences of elements are listed in order on a single line. For example, the Stream item consists of the constant TNEF_SIGNATURE, followed by a Key, followed by an Object. When an item has more than one possible implementation, the alternatives are listed on consecutive lines. For example, an Object can consist of a Message_Seq, a Message_Seq followed by an Attach_Seq, or just an Attach_Seq.

TNEF_Stream:
TNEF_SIGNATURE Key Object

Key:
a nonzero 16-bit unsigned integer

TNEF enabled transports generate this value before using the TNEF implementation to generate a TNEF stream.

Object:
Message_Seq
Message_Seq Attach_Seq
Attach_Seq

Message_Seq:
attTnefVersion
attTnefVersion Msg_Attribute_Seq
attTnefVersion attMessageClass
attTnefVersion attMessageClass Msg_Attribute_Seq
attMessageClass
attMessageClass Msg_Attribute_Seq
Msg_Attribute_Seq

attTnefVersion:
LVL_MESSAGE attTnefVersion sizeof(ULONG) 0x00010000 checksum

attMessageClass:
LVL_MESSAGE attMessageClass msg_class_length msg_class checksum

Msg_Attribute_Seq:
Msg_Attribute
Msg_Attribute Msg_Attribute_Seq

Msg_Attribute:
LVL_MESSAGE attribute-ID attribute-length attribute-data checksum

Attribute-ID is one of the TNEF attribute identifiers, such as attSubject. Attribute-length is the length in bytes of the attribute data. Attribute-data is the data associated with the attribute.

Attach_Seq:
attRenddata
attRenddata Att_Attribute_Seq

attRenddata:
LVL_ATTACHMENT attRenddata sizeof(RENDDATA) renddata checksum

Renddata is the data associated with the RENDDATA structure containing the rendering information for the corresponding attachment. The RENDDATA structure is defined in the tnef.h header file.

Att_Attribute_Seq:
Att_Attribute
Att_Attribute Att_Attribute_Seq

Att_Attribute:
LVL_ATTACHMENT attribute-ID attribute-length attribute-data checksum

Attribute-ID, attribute-length, and attribute-data have the same meanings as for the Msg_Attribute item.

Mapping of TNEF Attributes to MAPI Properties

The following table lists all the attributes defined in the TNEF implementation and their mappings to MAPI properties. In some cases, multiple MAPI properties are encoded as a single attribute. Some attributes have extended descriptions later in this appendix.
TNEF attribute MAPI property or properties
attAidOwnerPR_OWNER_APPT_ID
attAttachCreateDatePR_CREATION_TIME
attAttachDataPR_ATTACH_DATA_BIN or PR_ATTACH_DATA_OBJ
attAttachmentFor information about this mapping, see "Comments About the Attributes" later in this chapter
attAttachMetaFilePR_ATTACH_RENDERING
attAttachModifyDatePR_LAST_MODIFICATION_TIME
attAttachRenddataPR_ATTACH_METHOD, PR_RENDERING_POSITION
attAttachTitlePR_ATTACH_FILENAME
attAttachTransportFilenamePR_ATTACH_TRANSPORT_NAME
attBodyPR_BODY
attConversationIDPR_CONVERSATION_KEY. See attConversationID and attParentID for details.
attDateEndPR_END_DATE See attDate Attributes for details.
attDateModifiedPR_LAST_MODIFICATION_TIME See attDate Attributes for details.
attDateRecdPR_MESSAGE_DELIVERY_TIME See attDate Attributes for details.
attDateSentPR_CLIENT_SUBMIT_TIME See attDate Attributes for details.
attDateStartPR_START_DATE See attDate Attributes for details.
attFromPR_SENDER_ENTRYID and PR_SENDER_NAME
attMAPIPropsFor information about this attribute, see attMAPIProps.
attMessageClassPR_MESSAGE_CLASS
attMessageIDPR_SEARCH_KEY See TNEF Correlation in X.400 Gateways and Transports.
attMessageStatusPR_MESSAGE_FLAGS
attOriginalMessageClassPR_ORIG_MESSAGE_CLASS
attOwnerSee attOwner for details.
attParentIDPR_PARENT_KEY See attConversationID and attParentID for details.
attPriorityPR_PRIORITY
attRecipTablePR_MESSAGE_RECIPIENTS
attRequestResPR_RESPONSE_REQUESTED
attSentForPR_SENT_REPRESENTING_ENTRYID
attSubjectPR_SUBJECT
attTnefVersionFor information about this attribute, see

Comments About the Attributes

This section provides additional information about certain TNEF attributes. For more information about the MAPI properties that the attributes are mapped to, see the reference entries for the individual properties.

attMAPIProps

The attMAPIProps attribute is special in that it can be used to encode any MAPI property that does not have a counterpart in the set of existing TNEF-defined attributes. The attribute data is a counted set of MAPI properties laid end-to-end. The format of this encoding, which allows for any set of MAPI properties, is as follows:

Property_Seq:
property-count Property_Value, ...

There must be as many Property_Value items as the property-count value indicates.

Property_Value:
property-tag Property
property-tag Proptag_Name Property

The property-tag is simply the value associated with the property identifier, such as 0x003700001F for PR_SUBJECT.

Property:
Value
value-count Value, ...

Value:
value-data
value-size value-data padding
value-size value-IID value-data padding

Proptag_Name:
name-guid name-kind name-id
name-guid name-kind name-string-length name-string padding

The encapsulation of each property varies based on the property identifier and the property type. Property tags, identifiers, and types are defined in the mapitags.h and mapidefs.h header files.

If the property is a named property, then the property tag is immediately followed by the MAPI property name, consisting of a globally unique identifier (GUID), a kind, and either an identifier or a Unicode string.

Multivalued and properties with variable length values, such as the PT_BINARY, PT_STRING8, PT_UNICODE, or PT_OBJECT property types, are treated in the following way. First the number of values, encoded as a 32-bit unsigned long, is placed in the TNEF stream, followed by the individual values. Each property's value-data is encoded as its size in bytes followed by the value-data itself. The value-data is padded out to a 4-byte boundary, although the amount of padding is not included in the value-size.

If the property is of type PT_OBJECT, the value-size is followed by the interface identifier of the object. The current implementation of TNEF only supports the IID_IMessage, IID_IStorage, and IID_Istream interface identifiers. The size of the interface identifier is included in the value-size.

If the object is an embedded message (that is, it has a property type of PT_OBJECT and an interface identifier of IID_IMessage), the value data is encoded as an embedded TNEF stream. The actual encoding of an embedded message in TNEF implementation is done by opening a second TNEF object for the original stream and processing the stream inline.

attDate Attributes

All MAPI properties relating to dates and times are mapped to TNEF attributes that have the attDate prefix. These are all encoded as DTR structures. The dates and times for attachment attributes are encoded as DTR structures as well.

A DTR structure is very similar to the SYSTEMTIME structure defined in the Win32 header files. The DTR structure is encoded in the TNEF stream as sizeof(DTR) bytes starting with the first member of the structure. The DTR structure is defined in the tnef.h header file.

attOriginalMessageClass

A message class is stored as a string. The encoded string usually holds the MAPI-specified name of the message class. The exception is that to provide compatibility with Microsoft Mail for Windows for Workgroups 3.1, the following MAPI message classes are mapped to the following Microsoft Mail for Windows for Workgroups 3.1 message classes:
MAPI message class Windows for Workgroups Mail 3.x
IPMIPM.Microsoft Mail.Note
IPM.NoteIPM.Microsoft Mail.Note
IPM.Schedule.Meeting.CanceledIPM.Microsoft Schedule.MtgCncl
IPM.Schedule.Meeting.RequestIPM.Microsoft Schedule.MtgReq
IPM.Schedule.Meeting.Resp.NegIPM.Microsoft Schedule.MtgRespN
IPM.Schedule.Meeting.Resp.PosIPM.Microsoft Schedule.MtgRespP
IPM.Schedule.Meeting.Resp.TentIPM.Microsoft Schedule.MtgRespA
Report.IPM.Note.NDRIPM.Microsoft Mail.Non-Delivery
Report.IPM.Note.RNIPM.Microsoft Mail.Read Receipt

attConversationID and attParentID

The Windows for Workgroups 3.1 Mail conversation key is a text string. The MAPI equivalent is a binary value. To provide backward compatibility, the TNEF implementation converts the binary data to text and adds a terminating null character.

attFrom

The attFrom attribute is encoded as a TRP structure which encodes the display name and email address of the sender, followed by the display name and address of the sender, followed by any necessary padding. The format for attFrom is as follows:

attFrom:
TRP-structure
sender-display-name sender-address padding

The sender-display-name is a null-terminated string that is padded with an additional null character, if necessary, to reach a 2-byte boundary. The padding at the end of the attFrom encoding consists of as many null characters as needed to reach a sizeof(TRP) boundary.

TRP-structure:
trpidOneOff cbgrtrp cch cb

For the attFrom item, the TRP-structure is always a one-off encoding, so the trpid of the TRP-structure field is always trpidOneOff. The cbgrtrp, cch, and cb items correspond to the remaining fields of the TRP structure.

The cbgrtrp field is calculated as the sum of (sizeof(TRP) *2), the length of the null-terminated sender-display-name with its padding, and the length of the null-terminated sender-address.

The cch field is calculated as the length of the null-terminated display-name with its padding.

The cb field is calculated as the length of the null-terminated sender-address.

sender-address:
address-type : address '\0'

The sender-address is a string that is composed of four parts, the address-type, a literal colon (:), the address itself, and a terminating null character. For example, the string "fax:1-909-555-1234\0" would be a legal sender-address value.

attOwner

The attOwner attribute is encoded as counted strings laid end-to-end. The format for attOwner is as follows:

attOwner:
display-name-length display-name address-length email-address

email-address
type : address

Unlike other length values, the display-name-length and address-length are unsigned 16 bit values instead of unsigned long integers. They still include terminating null characters, however. The type and address strings in the email-address entry are separated by a literal colon (:) character, such as "smtp:joe@nowhere.com". Only the combined type:address string is null-terminated.

The mapping of MAPI properties to the attOwner attribute is dependent on the message class of the message being encoded. If the message is either a Microsoft Schedule+ meeting request or cancellation, then attOwner encodes one of the PR_SENT_REPRESENTING properties. If the message is a Microsoft Schedule+ meeting response of any type, then attOwner encodes one of the PR_RCVD_REPRESENTING properties.

attSentFor

The attSentFor attribute is encoded as counted strings laid end-to-end. The format for attSentFor is as follows:

attSentFor:
display-name-length display-name address-length email-address

email-address
type : address

Unlike other length values, the display-name-length and address-length are unsigned 16 bit values instead of unsigned long integers. They still include terminating null characters, however. The type and address strings in the email-address entry are separated by a literal colon (:) character, such as "smtp:joe@nowhere.com". Only the combined type:address string is null-terminated.

attRecipTable

When a recipient table is being encoded, each recipient is encoded as a row of MAPI properties. The format is as follows:

Row_Seq:
row-count
Property_Sequence, ...

The format of Property_Seq is the same as in the attMAPIProps attribute.

attPriority

MAPI message priorities are also mapped to Microsoft Mail 3.1 priority values for backward compatibility as follows:
PriorityMAPI value TNEF value
normal-13
high02
low11

attMessageStatus

MAPI message flags are mapped to Microsoft Mail 3.1 values to preserve backward compatibility. All the flags are grouped together and encoded in a single byte. The mappings are as follows:
MAPI message flags TNEF flags
MSGFLAG_READfmsRead
MSGFLAG_UNMODIFED~fmsModified
MSGFLAG_SUBMITfmsSubmitted
MSGFLAG_HASATTACHfmsHasAttach
MSGFLAG_UNSENTfmsLocal

These flags are defined in the tnef.h header file.

attAttachRenddata

The attAttachRenddata attribute is encoded as a RENDDATA structure that describes how and where the attachment is rendered in the message text. The RENDDATA structure is simply encoded in the TNEF stream as sizeof(RENDDATA) bytes beginning with the first member of the RENDDATA structure. If the value of the RENDDATA structure's dwFlags member is set to MAC_BINARY, then the data for the following attachment is stored in MacBinary format; otherwise, the attachment data is encoded as usual.

OLE Attachments

Attachments that are OLE objects are encoded as OLE 1.0 stream objects for backward compatibility with Microsoft Mail 3.x. If the original object is really an OLE 2.0 IStorage object, then the object must be converted to an OLE 1.0 stream. This conversion is performed using OleConvertIStorageToOLESTREAM function, which part of the Win32 OLE libraries; examples of this conversion can be found in OLE Programmer's Reference, Volume One.

TNEF Correlation

Some messaging systems perform a correlation check on any TNEF stream attached to an inbound message to verify that the TNEF stream does in fact belong to that message. This involves matching the value of some field in the header of the inbound message with a copy of that value stored in some property in the TNEF stream. Values that are presumably unique for each message, such as message ID numbers, are typically used for this. The transport or gateway the created the TNEF stream is responsible for choosing an appropriate value from the message header and placing a copy into an appropriate property before encoding the outgoing message's properties into the TNEF stream. Gateways or transports that receive the message can then extract that property from the TNEF stream and verify that its value matches the value of the corresponding header field on the inbound message.

If the values do not match, the gateway or transport should discard the TNEF stream and processes only the native message envelope. Such checks are prudent because non-MAPI-based mail clients may attach a file containing a TNEF stream from an old message to a forwarding or even an unrelated message; if not checked, such an error may result in the loss of message text.

The header field value chosen must be unique to the message. There is no fixed header field for all messaging systems because different messaging systems use different header fields, but typically the messaging system assigns a unique identifier to the message which is suitable for this purpose. For example, SMTP systems typically use the MessageID header, while X.400 systems typically use the IM_THIS_IPM attribute.

TNEF Correlation in SMTP Gateways and Transports

Gateways and transports that connect to Internet based systems, those that use SMTP, use the value of the MessageID SMTP header and the PR_TNEF_CORRELATION_KEY property to implement TNEF correlation.

The value of the MessageID header of the outbound message should be copied to the PR_TNEF_CORRELATION_KEY property and encoded in the attMAPIProps attribute of the TNEF stream. Note that PR_TNEF_CORRELATION_KEY is a binary property, while the MessageID is a string; the null terminator should be included in the copy and in the comparison.

This technique is used by all Microsoft software that connects MAPI-based messaging systems to the Internet, such as Microsoft Mail 3.x and Microsoft Exchange Server. This technique should be used by any SMTP gateways and transports that connect to systems that support MAPI clients in order to maximize interoperability.

TNEF Correlation in X.400 Gateways and Transports

Gateways and transports that connect to X.400 based systems, use the value of the IM_THIS_IPM X.400 attribute and the attMessageID TNEF attribute to implement TNEF correlation.

The value of the IM_THIS_IPM attribute of the outbound message is copied to attMessageID in the TNEF stream. The IM_THIS_IPM X.400 attribute is typically a string, while the attMessageID TNEF attribute is a string of hexadecimal digits representing a binary value. Therefore, each character in the IM_THIS_IPM X.400 attribute, including the terminating null character, must be converted to a 2-character hexadecimal string representing the ASCII value of that character. For instance, if the IM_THIS_IPM X.400 attribute is the following string:

3030322D3030312D305337533A3A3936303631312D313533373030

then the value of attMessageID would be the following sequence of hexadecimal digits:

33 30 33 30 33 32 32 44

33 30 33 30 33 31 32 44

33 30 35 33 33 37 35 33

33 41 33 41 33 39 33 36

33 30 33 36 33 31 33 31

32 44 33 31 33 35 33 33

33 37 33 30 33 30 00

This technique is used by the Microsoft Exchange Server X.400 Connector. This technique should be used by any X.400 gateways and transports that connect to Microsoft Exchange Server in order to maximize interoperability.

For greatest compatibility with future as well as present Microsoft software, the IM_THIS_IPM X.400 attribute should also be copied to the PR_TNEF_CORRELATION_KEY property. However, since PR_TNEF_CORRELATION_KEY is a binary property, no translation into a hexadecimal string is necessary.