65.9K
CodeProject is changing. Read more.
Home

Send HTML Via SMTP By Extending CMimeMessage

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.18/5 (6 votes)

Jan 18, 2007

CPOL

2 min read

viewsIcon

41304

downloadIcon

299

Extending the CMimeMessage class to send HTML messages

Introduction

I had a project recently that required sending emails with HTML content. I found an article by PJ Naughter on CodeProject that provided a couple of nice classes from Microsoft that are included in the Visual Studio 8.0 (Visual Studio 2005) development package.  These classes are CMimeMessage and CSMTPConnection.  This article explains how to use these classes to easily send email messages.

I looked through the CMimeMessage class to see if there was a way to use it without modification to send emails with HTML content and didn't see a clear path, but may be wrong.  I searched the internet for a while and found that some others were asking the same question.  I didn't find an answer.

So I decided to extend the CMimeMessage class to add a function that would add Text as HMTL to the Mail Message. It turned out to be pretty simple and could be done inline.

The Code

The first thing that I had to do was to extend the CMimeText class, as it has a function MakeMimeHeader that is automatically called to generate the email header for the Mime Section that it represents. I named this class CMimeHtml

I just simply copied the MakeMimeHeader function from the existing CMimeText class. The only modification was to replace the Content-Type: text/plain with Content-Type: text/html:

// This function is a copy of the CMimeText::MakeMimeHeader function. It has been
// updated to change the Content-Type text/html rather than text/plain.
//
// Make the MIME header
virtual inline BOOL MakeMimeHeader(CStringA& header, LPCSTR szBoundary) throw()
{
char szBegin[256];
if (*szBoundary)
{
// this is not the only body part

Checked::memcpy_s(szBegin, sizeof(szBegin), 
	ATLMIME_SEPARATOR, sizeof(ATLMIME_SEPARATOR));
Checked::memcpy_s(szBegin+6, sizeof(szBegin)-6, szBoundary, 
ATL_MIME_BOUNDARYLEN);
*(szBegin+(ATL_MIME_BOUNDARYLEN+6)) = '\0';
}
else
{
// this is the only body part, so output the full MIME header
Checked::memcpy_s(szBegin, sizeof(szBegin), ATLMIME_VERSION, sizeof(ATLMIME_VERSION));
}
_ATLTRY
{
// Here you can see that the Content-Type is text/html instead of text/plain. This is
// the only thing that makes the email message come out as text or html is this
// Content-Type marker that is written in the section header.
header.Format("%s\r\nContent-Type: 
text/html;\r\n\tcharset=\"%s\"\r\nContent-Transfer-Encoding: 
8bit\r\n\r\n", 
szBegin, m_szCharset);
return TRUE;
}

_ATLCATCHALL()
{
return FALSE;
}
}

The next step was to add a function to the CMimeMessage class to add an HTML Mime section. So I called the function AddHtml. I copied the code from the AddText function of the existing CMimeMessage class. I named this class CExtMimeMessage

The only modification here is to replace the CMimeText class with our extended CMimeHtml class:

// Pretty much taken from the Microsoft CMimeMessage::AddText function.
// The only difference is that we add a CMimeHtml class to the BodyParts
// list instead of a CMimeText class.
//
// Add some text to the message at position nPos in the body parts list
// szText - the text
// nTextLen - the size of the text in bytes 
// (optional - if not specified a _tcslen will be done)
// nPos - the position in the message at which to insert the text (optional)
// uiCodePage - the codepage (optional)

inline BOOL 
AddHtml(LPCTSTR szText, int nTextLen = -1, int 
nPos = 1, UINT uiCodePage = 0) throw()
{
if (szText == NULL)
return FALSE;
if (nPos < 1)
{
nPos = 1;
}

CAutoPtr<CMimeBodyPart> spNewText;
// Note that we are simply using the CExteMimeHtml Class (Extended CMimeText)
// The extended part is that the MakeMimeHeader function makes the Content-Type
// text/html instead of text/plain

CExtMimeHtml *pNewText = NULL;
ATLTRY(spNewText.Attach(pNewText = new CExtMimeHtml()));
if (!spNewText || 
!pNewText)
return FALSE;
BOOL bRet = pNewText->Initialize(szText, nTextLen, m_spMultiLanguage, 
uiCodePage);
if (bRet)
{
_ATLTRY
{
POSITION currPos = m_BodyParts.FindIndex(nPos-1);
if (!currPos)
{
if 
(!m_BodyParts.AddTail(spNewText))
bRet = FALSE;
}
else
{
if 
(!m_BodyParts.InsertBefore(currPos, spNewText))
bRet = FALSE;
}
}
_ATLCATCHALL()
{
bRet = FALSE;
}
}
return bRet;
}

All done.  All you have to do is copy in the included ExtMimeMessage.h file into your project, include "ExtMimeMessage.h", and use the CExtMimeMessage class in exactly the same way that you would have used the original CMimeMessage class.

I haven't seen any errors from using this class, but am open to all comments.

History

  • 18th January, 2007: Initial post