Update february 2016: Now the project compiles without the deprecated compiler switch '/clr:oldsyntax'.

Why using vmime ?

I was searching for a SMTP/POP3/IMAP library. What I found were either very expensive commercial libraries or free libraries without encryption support. Today many SMTP servers demand a TLS or SSL connection. With an email library that does not support encryption you will not be able to send an email to a Gmail SMTP server.

Finally I found vmime, which is a multi platform library for SMTP, POP3, IMAP, SendMail and MailDir with very cleanly written code and hosted on Github, mainly written by Vincent Richard, who did a great work.

A nightmare begins...

But this library is a Gnu project that was developed and tested mainly in the Mac / Linux world. Theoretically it should be possible to compile it on Windows with the Cmake compiler, but that threw a lot of cryptic error messages that I never saw before, so I gave up.

Additionally CMake is useless if you want to write a Managed C++ project for .NET. So I had to find a way to compile this stuff on Visual Studio. If you ever ported code from Linux to Windows you know what nightmare this is.

After eliminating all the errors in Visual Studio that you see whenever you compile a Linux project on Windows, I had the problem that the Config.hpp file was missing which contains all the project settings. I had to find out how to construct this file manually.

Then vmime depends on several other Gnu projects which I had to download separately:

GnuTLS or OpenSSL library for encryption,

iconv, a character set converter library,

gsasl, an authentication libary

All these libraries exist precompiled for Windows as DLLs and come with a Lib file for the linker. Some of them come with library files with names like "libgsasl.a". I never saw this file extension before and thought: These files are made for Windows so I change that to "libgsasl.lib". And the worst of all is that Visual Studio eats these files without complaining. But the compiled binary file will not run.
Finally I found out that these *.a files are for a Gnu compiler on Windows.
And where do I find the Lib files for Visual Studio?
They simply do not exist.
After investigating I found that I can create the Lib file from the Def file with a Visual Studio command line tool. See "libvmime\src\gsasl\CreateLIB.bat"

I started my first tests with GnuTLS which was an error, because:

GnuTLS depends on 4 more libraries (total 5 DLL's!)

None of these DLLs exists as 64 Bit version

It does not run correctly on Windows (throws Error "The TLS connection was non properly terminated" in the middle of an email transfer)

I wasted a lot of time with this library, finally I moved to OpenSSL which works perfectly.

The iconv library also caused me problems because there is no precompiled 64 Bit version for Windows and this library has apparently never been compiled for 64 Bit. Finally I replaced it with my own code that uses the Windows Codepage conversion API instead.

Problems with vmime

Then I started struggling with vmime code itself:

A severe lack was that vmime had no Unicode support. All strings are std::string while std::wstring was used in no place. Filenames were translated with the current ANSI codepage and passed to the ANSI file API (e.g. CreateFileA).

To permit that vmime can also be used by chinese or japanese users I had to find a way to pass unicode into vmime. I ended up converting all input strings in a wrapper class into UTF-8. Then, in the windows platform handler I convert the UTF-8 strings back to Unicode and pass them to widechar API (CreateFileW).

Another severe lack of vmime was the missing Trace output. When an error occurred with the server you had no idea what was the reason because you did not see the communication with the server. I implemented Trace support as you see in the screenshots below.

Another lack was that vmime code was not abortable. If the server did not respond the user had to wait until the timeout elapsed - up to 30 seconds! I fixed that.

Another problem was that in vmime error handling was not properly implemented.

Then I found several bugs, like for example openssl throwing "SSL3_WRITE_PENDING:bad write retry". I contacted Vincent - the author of vmime - who gave me excellent support with all problems and fixed some of these bugs.

Then I added new features that are indispensable for an easy usage like automatic mime type detection by file extension and loading root certificates from the resources.

The vmime library has been designed to be very flexible and expandable. This is good but has the disadvantage that the usage becomes awkward. For a simple task like extracting the plain text of an email you have to write a loop, enumerate all message parts, use a MessageParser, use a OutputStreamStringAdapter, a ContentHandler, a SmartPointer class, dynamic casts and character set conversion. All this is clumsy and an experienced programmer - new to vmime - easily needs some hours to find out how to do this. And for C++ beginners it will be nearly impossible to use vmime.
So I added wrapper classes that hide all this complicated stuff in a single function. (KISS principle )

Then I discovered a VERY weird phenomenon: Whenever in vmime an exception was thrown, I had memory leaks and TCP sockets that were not closed because several destructors were never called (no stack unwinding). You can read on Stackoverfow how I solved this.

I did a lot more things but to mention all this would be too much here.....
All my changes in the source code are marked with a comment: // FIX by Elmue , if you search so you find more than 240 modifications.

Finally...

...finally I was working two months on this project. I did really frustrating work and I nearly gave up more than once.

Now you are in the fortunate situation, that you can download a ready-to-use library that works perfectly and is very easy to use and intuitive.

EmailBuilder

With very few lines of code you can create a mime email with a plain text part, a Html part, embedded Html objects (e.g. images) and attachments. Both, plain text and Html text are optional. Modern email clients do not display the plain text part if a Html part is present.

if b_AllowInvalidCertificate == true an error is written to the Trace output,

if b_AllowInvalidCertificate == false an exception is thrown and the email is not sent.

Trace

The Trace output you see above is returned by vmime.NET via a callback. You can do whatever you like with it: write it to the console or display it in a log window or save it to a logfile. Or you turn off the compiler switch VMIME_TRACE and Trace is completely disabled.

A note about mass emails

If you plan to send for example a newletter with 500 recipients you will encounter lots of problems:

These measures are indispensable to fight spam that is mainly sent by Trojans and Botnets via SMTP. (Read about Trojans and Botnets in my article)
So the best solution to send a newletter is to install your own email server. (I recommend MDaemon Email Server)
But even with this solution you must be carefull because when your IP address gets listed on a blacklist your server may get blocked for multiple days.

Security

You have 4 options to send the email to the SMTP server: (enum e_Security)

on normal port (default 25) unencrypted. This deprecated option should be used only if the server is in the same intranet as you and only if there is no way to use the other options.

Both, SSL (Secure Sockets Layer) and TLS (Transport Layer Security) send the authentitication (user/password) and the email message encrypted.SSL starts immediately an encrypted connection.TLS is the successor of SSL. It starts with an unencrypted connection, sends the SMTP command "STARTTLS" and then encrypts the traffic on the same port.

Server Certificates

When using SSL or TLS the server authenticates itself with a X.509 certificate. vmime.NET has 185 built-in root certificates and checks that the server certificate is digitally signed with one of these root authorities (e.g. Verisign), that the expiration date of the certificate has not expired and that the hostname of the server is the same as in the certificate. With this certificate the client can prove that there is no man-in-the-middle attack.

NOTE:
Some POP3 servers do not respond on port 110 (e.g. Gmail) or reject a connection.
The only possible security mode for these servers is SSL (port 995).

IMPORTANT:Gmail has a very buggy POP3 behaviour: All emails can be downloaded only ONCE via POP3, no matter what setting you chose in your POP3/IMAP configuration! The emails are there in the web interface but pop.googlemail.com tells you that you have no emails in your Inbox. Or it may happen the opposite that POP3 shows you emails that have been deleted years ago (but only once)! Gmail's IMAP behaves normal.

Performance

When you fetch an email with i_Pop3.FetchEmailAt(M) only the mail header is downloaded (POP3 command "TOP"). This is quite fast and allows to access the Subject, From, To, Cc, Date, UserAgent, and more header fields.

When you call i_Email.GetSize() the POP3 command "LIST" is sent to the server to obtain the size of the email.

When you call i_Email.GetUID() the POP3 command "UIDL" is sent to the server to obtain the unique identifier of the email.

And when you access the body part of the email, the POP3 command "RETR" retrieves the entire email which may be slow if the email has serveral megabytes. The body contains the plain text, HTML text, embedded objects and attachments.

So, to improve performance you should access the body part only if you really need it.

IMAP

Imap has the same commands as Pop3.
Additionally there are:

C#

// Enumerate all folders on the server
String[] s_Folders = i_Imap.EnumFolders();
// Select the folder to retrieve emails from
i_Imap.SelectFolder("[Gmail]/Sent Mail");
// Get the current folder
String s_CurFolder = i_Imap.GetCurrentFolder();

C++

// Enumerate all folders on the server
void i_Imap.EnumFolders(vector<wstring>& i_FolderList);
// Select the folder to retrieve emails from
void i_Imap.SelectFolder(L"[Gmail]/Sent Mail");
// Get the current folder
wstring s_CurFolder = i_Imap.GetCurrentFolder();

As you see IMAP is far more complex than POP3. A new connection is established to the server each time a new folder is opened. (IMAP (1) is the first, IMAP (2) the second connection, etc...)

Performance

Here applies the same as for POP3, except that for obtaining Size and UID no additional command has to be sent to the server.

Deleting emails

The following code shows how to delete all emails with the subject "vmime.NET Test Email" that you have sent by the SMTP demo before to yourself.

IMPORTANT:POP3: When you call i_Pop3.Close() all emails marked for deletion are expunged definitely from the server. If you do not call Close() they will not be deleted!IMAP: When you call i_Email.Delete() the email is deleted immediately.

Download URL's

Here are the URL's where I downloaded the several components that are required to build the project.
You don't have to download them. This is just for your information.

Visual Studio 2005

If you use Visual Studio 2005 it is indispensable for this project to have VS Service Pack 1 installed. Otherwise you will see Intellisense hanging forever. This bug has been fixed in SP1. See MSDN.

Compiling and Dependencies

vmime.NET can be compiled as x86 (Win32) or x64 (Win64) and as Debug or Release.
There are two dependencies: GNU Sasl and OpenSsl.

The file cCommon.cpp contains the #pragma comment commands that tell the linker which Lib files to include depending on the current project settings.

The GSASL library consists of libgsasl-7.dll and the LIB files libgsasl-7_32.lib and libgsasl-7_64.lib.
If you should replace the Dll with another version you must also replace the Def file and run the script CreateLIB.bat to create the Lib files anew. Additionally the header files may have changed.

The OpenSSL library may be compiled dynamic (using ssleay32.dll and libeay32.dll) or static (no Dll's required)
When you run the OpenSSL installer for Windows you get a lot of LIB files:

The same amount of LIB files exist additionally for compiler switch /MT but this switch cannot be used in Managed C++ projects (vmime.NET.dll).
And the same amount of Lib files exists additionally for 64 Bit.
So there are totally 32 LIB files.

IMPORTANT:
If you should replace openssl with another version you must verify if the header files have changed.

Compiling vmime.NET.dll

I strongly recommend to link vmime.NET.dll statically because

The installer of your software has to deliver 2 Dlls less.

The openssl Dlls themself are dependent of the VC++ runtime 2008 (Msvcr90.dll).

If you compile on Visual Studio 2008 this does not matter because openssl is also compiled on VS2008, but on any other Visual Studio version it does:

vmime code itself also depends on the VC++ runtime but the version of the C++ runtime will depend on your Visual Studio version.
For example VS 2005 creates a dependency to Msvcp80.dll, Msvcr80.dll and Msvcm80.dll.

So, what would happen if you compile on VS 2005 and link dynamically to ssleay32.dll and libeay32.dll ?
Then your software would depend on Msvcp80.dll, Msvcr80.dll and Msvcm80.dll due to vmime and additionally on Msvcr90.dll which is required by ssleay32.dll and libeay32.dll.

This would mean that the users of your software have to install two VC++ runtimes!

Compiling Pure C++ Projects

All the above applies to vmime.NET.dll where the compiler switch /MT cannot be used (Visual Studio restriction).
But if you use vmime in a pure C++ project you can compile with /MT and use the openssl libraries libeay32MT.lib and ssleay32MT.lib instead.
This links the C++ runtime statically into your application and you do NOT need any of the MsvcXX.dll's.

DependencyWalker

If you are not sure on which Dlls your compiled binaries depend use DependencyWalker to check that:

This screenshot shows the depencies if compiled with openssl static LIB files on VS2005 as Release, 32 Bit.

IMPORTANT:
Microsoft's VC++ runtime installer does NOT install the Debug versions of these Dll's.
You MUST compile as Release before delivering your software!

ATTENTION:
If these DLL's are not installed on the target machine the user will NOT get an intelligent error message telling him what is wrong. Instead Microsoft .NET throws the most stupid exceptions like: "vmime.NET.dll or one of its dependencies could not be loaded" or "System.IO.FileLoadException:....This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem". The users of your application will never suspect that the cause is a missing MsVcXX.dll!

There are 2 ways to assure that the MsVcr/MsVcp/MsVcm DLLs exist on the target computer:

The users of your application must download and install the correct version of the Visual C++ Redistributable Package (see download links in table above). The files will be installed "side by side" into C:\Windows\WinSxS\Cryptic Folder.

Or you install the following files directly into the application folder as private assemblies: Microsoft.VCXX.CRT.manifest, msvcrXX.dll, msvcpXX.dll, msvcmXX.dll. You find these files in your Visual Studio folder under VC\Redist. The versions of these DLLs must be EXACTLY the same as those in the manifest compiled into vmime.NET.dll. You can read the following articles in the MSDN: Private Assemblies and Assembly Searching Sequence but probably you will get quite confused.

All these libraries exist precompiled for Windows as DLLs and come with a Lib file for the linker. Some of them come with library files with names like "libgsasl.a". I never saw this file extension before and thought: These files are made for Windows so I change that to "libgsasl.lib". And the worst of all is that Visual Studio eats these files without complaining. But the compiled binary file will not run. Finally I found out that these *.a files are for a Gnu compiler on Windows. And where do I find the Lib files for Visual Studio? They simply do not exist.After investigating I found that I can create the Lib file from the Def file with a Visual Studio command line tool. See "libvmime\src\gsasl\CreateLIB.bat"

From someone who's been in a similar situation, it struck a chord - I actually started out programming 'c' on Solaris/Unix platform, so the '.a' extension wouldn't have phased me - anyway, this isn't about me, its about you, and you did a great job of explaining the conversion process and pitfalls