IConverterSession – Do You Converter Session?


[This is now documented here: http://msdn2.microsoft.com/en-us/library/bb821176.aspx]

Ryan, one of our PMs over in Outlook, got an e-mail to his blog asking for a header for IConverterSession. He knows I’m the MAPI guy so he asked me if I could help out.

Here’s the header I use in MFCMAPI – it’s built directly from the docs:

#pragma once
//Class Identifiers
// {4e3a7680-b77a-11d0-9da5-00c04fd65685} 
DEFINE_GUID(CLSID_IConverterSession, 0x4e3a7680, 0xb77a,
	0x11d0, 0x9d, 0xa5, 0x0, 0xc0, 0x4f, 0xd6, 0x56, 0x85); 

//Interface Identifiers
// {4b401570-b77b-11d0-9da5-00c04fd65685} 
DEFINE_GUID(IID_IConverterSession, 0x4b401570, 0xb77b,
	0x11d0, 0x9d, 0xa5, 0x0, 0xc0, 0x4f, 0xd6, 0x56, 0x85);

// These are out of mimeole.h, which is a pain to include
typedef
enum tagMIMESAVETYPE
    {	SAVE_RFC822	= 0,
	SAVE_RFC1521	= SAVE_RFC822 + 1
    } 	MIMESAVETYPE;

typedef 
enum tagENCODINGTYPE
    {	IET_BINARY	= 0,
	IET_BASE64	= IET_BINARY + 1,
	IET_UUENCODE	= IET_BASE64 + 1,
	IET_QP	= IET_UUENCODE + 1,
	IET_7BIT	= IET_QP + 1,
	IET_8BIT	= IET_7BIT + 1,
	IET_INETCSET	= IET_8BIT + 1,
	IET_UNICODE	= IET_INETCSET + 1,
	IET_RFC1522	= IET_UNICODE + 1,
	IET_ENCODED	= IET_RFC1522 + 1,
	IET_CURRENT	= IET_ENCODED + 1,
	IET_UNKNOWN	= IET_CURRENT + 1,
	IET_BINHEX40	= IET_UNKNOWN + 1,
	IET_LAST	= IET_BINHEX40 + 1
    } 	ENCODINGTYPE;

// Constants
#define CCSF_SMTP		0x0002
#define CCSF_NOHEADERS		0x0004
#define CCSF_INCLUDE_BCC	0x0020
#define CCSF_USE_RTF		0x0080
#define CCSF_NO_MSGID		0x4000

interface IConverterSession : public IUnknown
{
	public:
	virtual HRESULT PlaceHolder1();
	virtual HRESULT STDMETHODCALLTYPE SetEncoding(ENCODINGTYPE et);
	virtual HRESULT PlaceHolder2();
	virtual HRESULT STDMETHODCALLTYPE MIMEToMAPI(LPSTREAM pstm,
			LPMESSAGE pmsg,
			LPCSTR pszSrcSrv,
			ULONG ulFlags);
	virtual HRESULT STDMETHODCALLTYPE MAPIToMIMEStm(LPMESSAGE pmsg,
			LPSTREAM pstm,
			ULONG ulFlags);
	virtual HRESULT PlaceHolder3();
	virtual HRESULT PlaceHolder4();
	virtual HRESULT PlaceHolder5();
	virtual HRESULT STDMETHODCALLTYPE SetTextWrapping(BOOL fWrapText,
			ULONG ulWrapWidth);
	virtual HRESULT STDMETHODCALLTYPE SetSaveFormat(MIMESAVETYPE mstSaveFormat);
	virtual HRESULT PlaceHolder8();
	virtual HRESULT PlaceHolder9();
};

Lemme know if I left anything out or made any mistakes and I’ll fix them up. Enjoy!

†Pardon the bad pun in the title. Couldn’t resist.

Comments (37)

  1. jamieb22 says:

    Hi there

    Thank you for getting back to me. I was in fact the developer who asked for this information, but I figured out on my own.  The header you posted is in fact in the MSDN library, but it is missing some crucial methods. For example, if you used the header as stated it would not produced RFC822 compliant messages as the email address fields would not be expanded correctly.

    This is the header that, with the help of others, I have constructed:

    [sgriffin here – I’ve excised this bit because it includes functions that we have not documented and I don’t want my blog to be used for reverse engineering.]

  2. Missing pieces? Sure! ๐Ÿ™‚

    1. PlaceHolder1 – still undocumented. And it is a pretty important piece.

    2. CCSF_USE_RTF – won’t work unless another bit (0x10) is also set. What is it?

    I am sure Lev can think of at least a dozen more missing pieces…

  3. I’m checking with dev to see if there’s any more of this API that we can document. That said – when I asked if I missed anything I meant did I leave out anything that has been documented. ๐Ÿ™‚

  4. jamieb22 says:

    Thank you for looking into this. We are left wondering whether Microsoft is deliberately trying to prevent people from converting MAPI messages to standard formats? This functionality should have been available long time ago!

    It would be nice if the MAPI engineering team would allow the rest of the world to interoperate with their proprietary system.

  5. kayli says:

    Is there some progress in this question?

    I think a lot of developer needs this informations. Will Microsoft document the missing functions of that interface?

  6. Good news, everyone! We’ve decided to document some more flags and functions for IConverterSession .

  7. fgouvea says:

    Hi Guys! IConverterSession would save my skin. But having the header file woulb pass the compile but not the linker. Wouldn`t I need a lib and dll as well?

    Thanks

  8. There’s no lib or DLL needed. You use CoCreateInstance. You should really crack open the MFCMAPI code and see how it’s done there.

  9. Rodrigo Mendes says:

    Hi there,

    I developed a code that receives the e-mail, converts the .wav message into the winmail.dat and sends it to the original destiny address. It’s working fine, but I’m having on problem when using the IConverterSession, more specifically when using the MAPItoMIMEStm.

    If I run my DLL into an environment that is sending the e-mail from WinXP plataform to an Exchange Server, my code works fine.

    But if I run my DLL into an environment that is sending the e-mail from Win2003 plataform to the same Exchange Server, I got the "MAPI_E_BAD_CHARWIDTH" error in the MAPItoMIMEStm line of code.

    Can you help to find out what is wrong ?

    Thanks in advance.

  10. IConverterSession is not an OS provided API. It’s provided by Outlook. What versions of Outlook do you have installed on these two machines?

  11. Rodrigo Mendes says:

    The machine where it works has Outlook 2003. The machine where does not work is a virtual machine, so we don’t have Outlook installed on it.

    Due to this, we copied and registered the same version of OUTLMIME.DLL that we have in the machine that it is working.  Is it possible that some other registration or even some other DLL is missing ?

  12. I don’t see why a machine being virtual would mean you wouldn’t have Outlook installed on it, but regardless, that’s the problem. Outlook has to be installed to use this API. You can’t go copying random DLLs and expect things to work.

  13. Rodrigo Mendes says:

    OK. So, there is no other way to use this API than installing (and not necessarily running) Outlook on this machine.

    Just for curiosity, how complex would be to implement the IConverterSession manually?

  14. It’s not a trivial API to implement. And you’d still need some version of MAPI installed on the machine.

  15. Roberto Taglia says:

    IConverterSession needs that Outlook (Office and Express) must be installed on the computer.

    If i install <Microsoft Exchange Server MAPI Client and Collaboration Data Objects 1.2.1> instead of Outlook, can i use IConverterSession to convert MSG to EML format (is this enough) ?

    What can you advice me to read MSG file format from C# !

    I found this <http://www.codeproject.com/KB/cs/MsgReader.aspx&gt; but from a MSG file, it only reads the plain text body and not the HTML body !

    Thank you

  16. Roberto Taglia says:

    By using MAPI (without Outlook), is it possible to read the HTML part of a MSG Outlook message ?

    All i want to do is to read the HTML part in C# if possible (I can convert code from C++).

    Without Outlook because i do not known if my application will run with Outlook installed or not ?

    Converting MSG to EML is not really necessary for me because i have component that create EML (RFC822). I only need to read the content of a MSG file format (especially the HTML part).

    Thank you very much for helping me.

  17. Roberto Taglia says:

    When using OutlookSpy, i took a mail message and i see that the HTML body part is the property PR_HTML WHEN i inspect only the mail message within Outlook from my folder "Receinving".

    When i saved the same mail message as MSG file format from the SaveAs Outlook menu. When i read it with OutlookSpy as an external file, the PR_HTML MAPI property is not used. To read the body part from this loaded mail message, i must use the PR_RTF_COMPRESSED MAPI property. But I do not known what to do with RTF. I need a HTML body part.

    Is there a setting in outlook in order to save a mail message in the PR_HTML MAPI property as HTML content ?

    By usin Outlook API, can i retrieve the HMTL body part from a MSG message. How to proceed by usin C# ?

    Thank you very much.

  18. ppeleshok says:

    Hello, might I ask how IConverterSession::SetEncoding works? Actually, is there a way to enforce Exchange MAPI to set the encoding to some specific value (ie. quoted-printable) or does it always just do it on its own?

    The closest MAPI property I could find was PR_SEND_INTERNET_ENCODING but it doesn’t seem to allow me to specify the actual encoding type. Since this interface allows Outlook to do it, I’m guessing I should be able to also do it directly using a MAPI property?

    Thanks in advance.

  19. SetEncoding just sets an internal variable used later during the conversion. It’s not setting anything on the message.

  20. ppeleshok says:

    Is there anything in the message that I could set so that I could enforce something like quoted-printable or base64 in the content-transfer-encoding? Are there other bits in PR_SEND_INTERNET_ENCODING that aren’t documented?

  21. Huzaifa Kagazwala says:

    I am using MAPIToMIMEStm function for creating an .eml file. It seems that the above function excludes some properties like PR_ICON_INDEX, which is used for showing colors assigned to notes and calendar items on the icon/envelope.

    Therefore when the file is again imported to outlook using MIMEToMAPI colors assigned to Notes are not visible on the envelope/icon though they are visible when the Notes is opened.

    The flags passed to MAPIToMIMEStm are CCSF_SMTP | CCSF_USE_TNEF | CCSF_USE_RTF. I have tried saving the file in RFC 822 and 1521 format but none them solve the problem.

    Is this a bug with IConvertorSession implementation? How can I add the above mentioned property to the .eml file?

  22. Sonali Gupta says:

    I am using IConverterSession interface in c #.

    I declared the Interface is this way –

    <lengthy code block excised>

    I created an Instance of IConverterSession.I tried calling methods SetEncoding(), SetSaveFormat() on that instance, these methods are executed successfully. But when I call MIMEToMAPI() on the same instance it gives following exception – “Attempted to read or write protected memory. This is often an indication that other memory is corrupt.”

    Here is the code I am using –

    <lengthy code block excised>

    I also tried using CoCreateInstance() instead of Activator.CreateInstance() but that also doesn’t helped.

    Any input on this will a great help.

    Thanks.

  23. Sonali – MAPI’s not supported with .Net. Since this interface requires MAPI, it wouldn’t be supported with .Net either.

  24. Huzaifa kagazwala says:

    MAPIToMIMEStm returns E_INVALIDARG for some messages, it works only if CCSF_NOHEADERS is passed along with CCSF_SMTP. I have tried all many different combinations of convector flags, also tried different encoding, storage format i.e. RFC  etc. Nothing works unless CCSF_NOHEADERS is passed. What could be the problem here.

    Tried the conversion with MFCMAPI and Outlook Spy.

  25. Huzaifa kagazwala says:

    If an email has To and Cc list empty, this can happen if mail is sent with users in Bcc only. On converting the mail to EML file the Sender is set in the To list.

    Is this a bug or an expected behavior.

  26. fbs says:

    Is there a bug in the Outlook 2007 MimetoMAPI function?  Granted it’s an interop situation (Exchange to our MAPI provider), but the exact same thing works in Outlook 2003 and Outlook 2010:

    Our user sends update of recurrence to Exchange user, changing the date an of occurrence.  Exchange user accepts.  MimeToMAPI can’t parse acceptance message — returns MAPI_W_PARTIAL_COMPLETION.  It works fine if we just change the time of the occurrence, but changing the date causes this problem only in Outlook 2007.

    These acceptance messages are multipart/alternative messages with the calendar part base64 encoded.  I base 64 decoded these, and they look fine.  The only appreciable differences between the good one (just changed time) and the bad one (changed date) are the X-MICROSOFT-CDO-APPT-SEQUENCE, SEQUENCE, and obviously the start times and RECURRENCE-IDs.  Syntactically, they’re all fine.

    This seems to point to a bug here.  Had you heard of such a bug?

    I use Outlook 2007 (12.0.6514.5000) SP2 MSO (12.0.6425.1000)

    Thanks

  27. Venkat says:

    Hi,

     I am facing couple problems with IConverterSession:

     1) IConverterSession is not able to convert bounced messages? I am getting E_INVALID return code ? Is this expected ?

     2) I see that the mailing list names are not resolved during translation ? I did SetAdrBook but still not working ? Any clues ?

  28. ver_amitabh says:

    I am using IConverterSession::MAPIToMime() but if any of the email address contains any non-ascii international character (e.g.testñemail@domain.com), resultant mime stream contains the ‘Q’ encoded email address where ‘@’also gets decoded and it becomes the invalid email address (e.g. <=?utf-8?Q?โ€™test=C3=B1email=40domain.comโ€™?=). Is it know issue? Any suggestion to make it working properly?

  29. pat says:

    Hi,

    I am using IConverterSession::MapiToMimeStm() with installed Outlook 2010 and Outlook 2007 – OUTLMIME.DLL crashes with an Access violation on some (not all) Outlook profiles.

    The callstack shows mlang.dll involved, but I don't get any symbols. Most of the time everything is working fine with the same calls (so I don't think my parameters are wrong). It's only happening on some PST files and Outlook profiles.

    Can you give me a hint regarding that issue? Is there a known issue in some situations / configurations?

    Thanks.

  30. Liron Newman says:

    I can't get MAPIToMIMEStm to work on Outlook 2013 Click-to-Run. When trying it through MFCMAPI by exporting with IConverterSession, I get this error:

    Error:

    Code: REGDB_E_CLASSNOTREG == 0x80040154

    Function lpConverter->MAPIToMIMEStm(lpMsg, lpMimeStm, ulConvertFlags)

    File MapiMime.cpp

    Line 113

    I ran fixmapi and tried repairing Office – it didn't help. It occurs on 32-bit and 64-bit installs.

    I see that OUTLMIME.DLL seems to be registered correctly under HKEY_LOCAL_MACHINESOFTWAREMicrosoftOffice15.0ClickToRunREGISTRYMACHINESoftwareClassesWow6432NodeCLSID{4E3A7680-B77A-11D0-9DA5-00C04FD65685}. I tried copying this subkey to HKLMSoftwareClassesWow6432NodeCLSID{4E3A7680-B77A-11D0-9DA5-00C04FD65685} but that didn't help either.

    Looking in ProcMon, I see that MFCMAPI finds the CLSID in the registry, then finds the path of the DLL, then "Load Image" succeeds for "C:Program FilesMicrosoft Office 15rootoffice15OUTLMIME.DLL".

    Checking API Monitor, I see:

    # Time of Day Thread Module API Return Value Error Duration

    7 3:58:22.974 PM 1 OUTLMIME.DLL CoCreateInstance ( {9eadbd1a-447b-4240-a9dd-73fe7c53a981}, NULL, CLSCTX_INPROC_SERVER, {fd853cd5-7f86-11d0-8252-00c04fd85ab4}, 0x003deb10 ) REGDB_E_CLASSNOTREG 0x80040154 = Class not registered 0.0005830

    What am I missing?

    Thanks!

  31. This is a known issue with the C2R version of Outlook. We're still working on how to approach fixing it. Just registering the classes is problematic because we now support C2R on the same machine as MSI installs of Outlook 2010, which depends on the classes it registered.

  32. Liron Newman says:

    Thanks Stephen! Is there any other way to do MAPIToMIME that is supported on Outlook 2013 C2R?

  33. If you can figure out how to load those interfaces without relying on the registry that would work.

  34. Liron Newman says:

    That's the strange thing – Based on the ProcMon and API Monitor results, it's clear that it *is* finding the correct DLL. The line where it gives the error isn't when trying to create the object, but rather when trying to call MAPIToMIMEStm.

    I'll wait for this to be fixed, then. I hope you'll post about it when it happens. ๐Ÿ™‚

    Thanks!

  35. If you think this might be a different issue I'd advise opening a case to have it investigated.

  36. Liron Newman says:

    Hi Stephen and everyone,

    After some testing, I found that it works if I copy the CLSID registry subkeys for both IConverterSession and IMimeMessage (see example below). Stephen, can you confirm whether IConverterSession would depend on additional classes (like IMimeInternational, IMimeSecurity, etc.), or is IMimeMessage always the only one?

    Here's the batch file I use to copy the required registry subkeys:

    rem For when the Office bitness matches Windows bitness:

    rem IConverterSession

    reg copy HKLMSOFTWAREMicrosoftOffice15.0ClickToRunREGISTRYMACHINESoftwareClassesCLSID{4E3A7680-B77A-11D0-9DA5-00C04FD65685} HKLMSOFTWAREClassesCLSID{4E3A7680-B77A-11D0-9DA5-00C04FD65685} /s /f

    rem IMimeMessage

    reg copy HKLMSOFTWAREMicrosoftOffice15.0ClickToRunREGISTRYMACHINESoftwareClassesCLSID{9EADBD1A-447B-4240-A9DD-73FE7C53A981} HKLMSOFTWAREClassesCLSID{9EADBD1A-447B-4240-A9DD-73FE7C53A981} /s /f

    rem For Office 32-bit on Windows 64-bit:

    rem IConverterSession

    reg copy HKLMSOFTWAREMicrosoftOffice15.0ClickToRunREGISTRYMACHINESoftwareClassesWow6432NodeCLSID{4E3A7680-B77A-11D0-9DA5-00C04FD65685} HKLMSOFTWAREClassesWow6432NodeCLSID{4E3A7680-B77A-11D0-9DA5-00C04FD65685} /s /f

    rem IMimeMessage

    reg copy HKLMSOFTWAREMicrosoftOffice15.0ClickToRunREGISTRYMACHINESoftwareClassesWow6432NodeCLSID{9EADBD1A-447B-4240-A9DD-73FE7C53A981} HKLMSOFTWAREClassesWow6432NodeCLSID{9EADBD1A-447B-4240-A9DD-73FE7C53A981} /s /f

    Is there a way to get App-V to virtualize HKLMSOFTWAREMicrosoftOffice15.0ClickToRunREGISTRYMACHINE* to HKLM* for my app, like it does for Office, so I can avoid this ugly hack?

    Thanks!

  37. Simón Medrano says:

    Hi, Stephen!

    Looking at the IConverterSession::SetEncoding documentation (and also answered in one of the comments above), I found that it only applies to "the outermost message body of a mail item" and that "Outlook chooses the encoding for any individual attachments".

    For a very specific application I need to have all attachments always encoded as base64 (I'm not concerned about the size of the resulting messages at all, just prefer base64 over any other Content-Transfer-Encoding in this particular case).

    Is there a way to tell the IConverterSession to use base64 encoding for all attachments, and not to use its internal statistical/magic encoding chooser when exporting messages with the MAPIToMIMEStm method?

    I'll really appreciate any help.

    Thanks!