Site Map Contact Us Home
E-mail Newsletter
Subscribe to get informed about
Clever Components news.

Your Name:
Your Email:
 
SUBSCRIBE
 
Previous Newsletters
 




Products Articles Downloads Order Support
Customer Portal      

Parse TNEF (Winmail.dat) Attachment in Delphi


TNEF Attachment Parser

Abstract

Transport Neutral Encapsulation Format (TNEF) is a proprietary email attachment format used by Microsoft Outlook when when sending a message using either Rich Text Format or HTML Format. An attached file with TNEF encoding is most often named winmail.dat or win.dat, and has a MIME type of "application/ms-tnef".

The Winmail.dat contains the rich text body, MAPI properties information, and original attachments. The given library provides the TNEF Reader to decode the Winmail.dat file and save the attached files to the disk.

The TNEF (winmail.dat) file format is described in the [MS-OXTNEF]: Transport Neutral Encapsulation Format (TNEF) Data Algorithm document at Microsoft Knowledge Base. It includes a set of variable-length blocks, named as attributes. There is a number of different attributes that stores the MAPI, text information, and file attachments. Some attributes consist of another structures - properties. All the necessary information is stored in both the attribute and property structures.
The other attributes contain an information about the attachment file name, MIME type, content disposition, and other useful information. Also, there is a set of attributes and properties that contains the MAPI information: the message subject, recipients, etc. The rich text body (RTF-formatted) is stored in a separated property and may be compressed using the proprietary RTF-compression algorithm.

In this article, we introduce the code that extracts the message attachments, with the original file names, and the message body, including HTML, text, and RTF.
Currently, the RFT compression algorithm has not been implemented yet and we are planning to add it later in this series.

Download on GitHub

 

Reading and decoding the TNEF structure

The TTnefReader is a class that includes algorithms for reading and decoding  the whole TNEF structure. It provides the ability to walk through the attributes and properties, and read the encoded information to the native Delphi types: strings, integers, and streams.
This class provides the low-level access to the TNEF data and allows extracting any MAPI, attachments, and other data, included in the input Winmail.dat file.

The usage of this class is relatively complicated. You need to create an instance of TTnefReader, supply the input stream, and enumerate the included attributes using the NextAttribute iterator method. Depending on the attribute type, you can read data using the simple ReadString / ReadBytes / ReadInt32 methods, or using the TTnefPropertyReader class for reading the TNEF properties and MAPI information.

// [Delphi]
reader := TTnefReader.Create(ASource);
try
   while reader.NextAttribute do
   begin
      if reader.AttributeLevel = alAttachment then
      begin
         //further reading
         //...
         if reader.AttributeTag = agAttachData then
         begin
            content := TFileStream.Create('filename.ext', fmCreate);
            attachDataAttr := TAttachDataAttribute.Create(reader, content);
            try
               attachDataAttr.Load;
            finally
               attachDataAttr.Free;
               content.Free;
            end;
         end;
         //...
      end;
   end;
finally
   reader.Free;
end;

There is one more class that simplifies the attachment extraction task: TTnefAttachmentParser. This class internally utilizes the TTnefReader and provides the Parse method that reads data from the provided stream and stores the extracted attachments to the destination folder. Since the information about the attachment file names is stored in the separated TNEF attributes, we need to extract it before creating the destination stream and reading the attachment content. The TTnefAttachmentParser class does all this work. There is a special helper class, TAttachmentInfo, that keeps the extracted attachment-related information.

The example below demonstrates how to use the TTnefAttachmentParser class in your code:

// [Delphi]
parser := TTnefAttachmentParser.Create;
stream := TFileStream.Create('winmail.dat', fmOpenRead);
try
   parser.Parse(stream, 'c:\downloads\tnef\');
finally
   stream.Free;
   parser.Free;
end;

You can use the TTnefAttachmentParser class as a starting point for developing your own functionality, extracting more information from the TNEF structure, saving attachments to memory or the database storage. When using together with E-mail reading Software, such as SMTP client from the Clever Internet Suite library, or any other third-party or the standard Indy Software, you can convert the MS Outlook-specific incoming mail to the most commonly used MIME format.

An example of retrieving a MS Outlook mail and extracting the included attachments is shown below:

// [Delphi]
procedure TForm1.btnRetriveMailClick(Sender: TObject);
var
   pop: TclPop3;
   msg: TclMailMessage;
   msgNo: Integer;
   parser: TTnefAttachmentParser;
   stream: TStream;
begin
   pop := TclPop3.Create(nil);
   msg := TclMailMessage.Create(nil);
   parser := TTnefAttachmentParser.Create;
   try
      msg.OnSaveAttachment := msgSaveAttachment;

      pop.Server := 'mailhost';
      pop.UserName := 'user@domain.com';
      pop.Password := 'secret';

      msgNo := 1;

      pop.Open;
      pop.Retrieve(msgNo, msg);
      pop.Close;

      if FileExists('winmail.dat') then
      begin
         stream := TFileStream.Create('winmail.dat', fmOpenRead);
         try
            parser.Parse(stream, 'c:\downloads\tnef\');
         finally
            stream.Free;
         end;
      end;

   finally
      parser.Free;
      msg.Free;
      pop.Free;
   end;
end;

// [Delphi]
procedure TForm1.msgSaveAttachment(Sender: TObject; ABody: TclAttachmentBody;
   var AFileName: string; var AData: TStream; var Handled: Boolean);
begin
   if (AFileName = 'winmail.dat') or (AFileName = 'win.dat') then
   begin
      AData := TFileStream.Create('winmail.dat', fmCreate);
      Handled := True;
   end;
end;

If you want to keep the Winmail.dat file in memory, you need to create a TMemoryStream instance instead of TFileStream, and use one more event - OnAttachmentSaved. This event is necessary to access the extracted Winmail.dat content.

 

Downloads

Download on GitHub

Clever Internet Suite Download

Ask a Question

 

License Information

The TNEF parser library is distributed under the GNU LESSER GENERAL PUBLIC LICENSE Version 3.

COPYING.txt

COPYING.LESSER.txt

 

Sergey Shirokov
Clever Components team
www.clevercomponents.com

    Copyright © 2000-2024