This article was previously published under Q171907
This article contains code that demonstrates how to save a message to a
compound document--specifically an .msg file--that is readable by any
client that supports the .msg file format.
The function below takes a valid message object as an in parameter and uses
its properties to create a duplicate of the message and save it to a
compound file using the .msg format. The subject line of the message is
used as the file name of the new file.
NOTE: Special characters in the subject line of the in parameter of this
function can cause unexpected results. While code can be written to avoid
special characters in the subject line, it is not germane to the topic and
such code is intentionally left out.
0x0000, 0x0000, 0xC0, 0x00, 0x0, 0x00, 0x0, 0x00, 0x00, 0x46);
HRESULT SaveToMSG ( LPMESSAGE pMessage )
HRESULT hRes = S_OK;
LPSPropValue pSubject = NULL;
LPSTORAGE pStorage = NULL;
LPMSGSESS pMsgSession = NULL;
LPMESSAGE pIMsg = NULL;
SizedSPropTagArray ( 7, excludeTags );
LPWSTR lpWideCharStr = NULL;
ULONG cbStrSize = 0L;
// create the file name in the directory where "TMP" is defined
// with subject as the filename and ".msg" extension.
// get temp file directory
// get subject line of message to copy. This will be used as the
// new file name.
HrGetOneProp( pMessage, PR_SUBJECT, &pSubject );
// fuse path, subject, and suffix into one string
strcpy ( strAttachmentFile, szPath );
strcat ( strAttachmentFile, pSubject->Value.lpszA );
strcat ( strAttachmentFile, ".msg");
// get memory allocation function
LPMALLOC pMalloc = MAPIGetDefaultMalloc();
// Convert new file name to WideChar
cbStrSize = MultiByteToWideChar (CP_ACP,
-1, lpWideCharStr, 0);
MAPIAllocateBuffer ( cbStrSize * sizeof(WCHAR),
(LPVOID *)&lpWideCharStr );
-1, lpWideCharStr, cbStrSize );
// create compound file
hRes = ::StgCreateDocfile(lpWideCharStr,
STGM_CREATE, 0, &pStorage);
// Open an IMessage session.
hRes = ::OpenIMsgSession(pMalloc, 0, &pMsgSession);
// Open an IMessage interface on an IStorage object
hRes = ::OpenIMsgOnIStg(pMsgSession,
NULL, 0, 0, &pIMsg);
// write the CLSID to the IStorage instance - pStorage. This will
// only work with clients that support this compound document type
// as the storage medium. If the client does not support
// CLSID_MailMessage as the compound document, you will have to use
// the CLSID that it does support.
hRes = WriteClassStg(pStorage, CLSID_MailMessage );
// Specify properties to exclude in the copy operation. These are
// the properties that Exchange excludes to save bits and time.
// Should not be necessary to exclude these, but speeds the process
// when a lot of messages are being copied.
excludeTags.cValues = 7;
excludeTags.aulPropTag = PR_ACCESS;
excludeTags.aulPropTag = PR_BODY;
excludeTags.aulPropTag = PR_RTF_SYNC_BODY_COUNT;
excludeTags.aulPropTag = PR_RTF_SYNC_BODY_CRC;
excludeTags.aulPropTag = PR_RTF_SYNC_BODY_TAG;
excludeTags.aulPropTag = PR_RTF_SYNC_PREFIX_COUNT;
excludeTags.aulPropTag = PR_RTF_SYNC_TRAILING_COUNT;
// copy message properties to IMessage object opened on top of
hRes = pMessage->CopyTo(0, NULL,
pIMsg, 0, NULL );
// save changes to IMessage object.
pIMsg -> SaveChanges ( KEEP_OPEN_READWRITE );
// save changes in storage of new doc file
hRes = pStorage -> Commit(STGC_DEFAULT);
// free objects and clean up memory
MAPIFreeBuffer ( lpWideCharStr );
CloseIMsgSession ( pMsgSession );
pStorage = NULL;
pIMsg = NULL;
pMsgSession = NULL;
lpWideCharStr = NULL;
All versions of Outlook and the Exchange Client support CLSID_MailMessage as the compound document. The only reason to use a different CLSID is to support other clients that use a different CLISD when you write messages to structured storage.
When saving messages which have a large number of recipients or attachments, it is possible that the CopyTo operation will fail with MAPI_E_NOT_ENOUGH_MEMORY. This is due to a known problem with structured storage and streams. Every time that a new attachment or recipient is added to the message being saved in structured storage, a new Root Storage File is opened. These files are not closed until the transaction is completed. Because the operating system imposes a limit on the number of simultaneously open root storage files, there is no known workaround. For additional information, click the article number below
to view the article in the Microsoft Knowledge Base:
Limit of the Number of Simultaeously Open Root Storage Files
All versions of Outlook are affected by this limitation as well.
Article ID: 171907 - Last Review: August 18, 2005 - Revision: 2.5
- Microsoft Office Outlook 2007
- Microsoft Messaging Application Programming Interface
- Microsoft Exchange Client 5.5
- Microsoft Exchange Client 5.0
- Microsoft Exchange Client 4.0
- Microsoft Exchange Client 5.0