<

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x

Sending Email with MAPI

Published on
21,034 Points
16,534 Views
Last Modified:
Introduction

In this article I will provide runnable examples - create an empty Win32 application project in Visual Studio, add new cpp-file and cut-n-paste the source code.

Sending email with ShellExecute

If you have a task to send an email from your C/C++ application a very simple solution is to use ShellExecute. The following Win32 application sends a text with a subject to a recipient:

 
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <ShellAPI.h>

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
					LPWSTR lpCmdLine, int nCmdShow)
{
	ShellExecute(NULL, L"open", 
		L"mailto:someone@somewhere.com\
		 ?Subject=Hello, world\
		 &body=The email sent from ShellExecute", 
		L"", L"", SW_SHOWNORMAL );
	return 0;
}

Open in new window


So little code always works regardless of the OS version or mail client.

Simple MAPI

If you'd prefer a longer and more complicated way, you can choose Simple MAPI. The following application also sends email from your mail client:

 
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <mapi.h>

BOOL SendMail(LPCSTR lpszSubject, LPCSTR lpszTo, 
	  LPCSTR lpszName, LPCSTR lpszText);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
	LPWSTR lpCmdLine, int nCmdShow)
{
	SendMail("Hello", "SMTP:someone@somewhere.com", 
		"Name", "Text");
	return 0;
}

BOOL SendMail(LPCSTR lpszSubject, LPCSTR lpszTo, 
	LPCSTR lpszName, LPCSTR lpszText)
{
	HINSTANCE hMAPI = ::LoadLibrary(L"mapi32.dll");
	LPMAPISENDMAIL lpfnMAPISendMail = 
		(LPMAPISENDMAIL)::GetProcAddress(hMAPI, "MAPISendMail");

	char szTo[MAX_PATH] = { 0 };
	strcat_s(szTo, lpszTo);

	char szName[MAX_PATH] = { 0 };
	strcat_s(szName, lpszName);

	MapiRecipDesc recipient[1] = { 0 };
	recipient[0].ulRecipClass = MAPI_TO;
	recipient[0].lpszAddress = szTo;
	recipient[0].lpszName = szName;

	char szSubject[MAX_PATH] = { 0 };
	strcat_s(szSubject, lpszSubject);

	char szText[MAX_PATH] = { 0 };
	strcat_s(szText, lpszText);

	MapiMessage MAPImsg = { 0 };
	MAPImsg.lpszSubject = szSubject;
	MAPImsg.lpRecips = recipient;
	MAPImsg.nRecipCount = 1;
	MAPImsg.lpszNoteText = szText;

	ULONG nSent = lpfnMAPISendMail(0, 0, 
		&MAPImsg, MAPI_LOGON_UI | MAPI_DIALOG, 0);

	FreeLibrary(hMAPI);
	return (nSent == SUCCESS_SUCCESS || nSent == MAPI_E_USER_ABORT);
}

Open in new window


Function SendMail loads the appropriate system DLL (mapi32.dll) and, with GetProcAddress, retrieves the pointer to the MAPISendMail function:

 
HINSTANCE hMAPI = ::LoadLibrary(L"mapi32.dll");
LPMAPISENDMAIL lpfnMAPISendMail = 
	(LPMAPISENDMAIL)::GetProcAddress(hMAPI, "MAPISendMail");

Open in new window


Note. In a real project the hMAPI handle should be verified, that it is not NULL, before the use in the following GetProcAddress function call.

Information about the message that is going to be sent is stored in MapiMessage structure:

 
MapiMessage MAPImsg = { 0 };
MAPImsg.lpszSubject = szSubject;
MAPImsg.lpRecips = recipient;
MAPImsg.nRecipCount = 1;
MAPImsg.lpszNoteText = szText;

Open in new window


where the recipient is an array:

 
MapiRecipDesc recipient[1] = { 0 };
recipient[0].ulRecipClass = MAPI_TO;
recipient[0].lpszAddress = szTo;
recipient[0].lpszName = szName;

Open in new window


that allows to set many recipients.

Pay attention that SendMail function received the constant strings as the parameters, such as "Hello" for the email subject or "SMTP:someone@somewhere.com" for the address. Inside the function I converted these constant strings into the pointers (LPSTR) and used them to fullfill the the MAPI structures.

When a mail client, for example, Outlook, is running, it is possible to prepare and send the message in a "silent" mode - without prompting the user to press the button Send and do not show the New Message dialog. For that purpose, in the sample code above, the fourth parameter in the MAPISendMail call should be replaced with NULL:

 
ULONG nSent = pMAPISendMail(0, 0, &MAPImsg, NULL, 0);

Open in new window


Attachment

You can attach a file to your email as it is shown here:

 
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <stdlib.h>
#include <mapi.h>

BOOL SendFile(LPCSTR lpszSubject, LPCSTR lpszTo, 
	  LPCSTR lpszName, LPCSTR lpszText, 
	  LPCSTR lpszFullFileName);


int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
	LPWSTR lpCmdLine, int nCmdShow)
{
	SendFile("Hello", "SMTP:somebody@nowhere.com", 
		"Cool Guy", "Message Text", "c:\\text.txt");
	return 0;
}

BOOL SendFile(LPCSTR lpszSubject, LPCSTR lpszTo, 
	  LPCSTR lpszName, LPCSTR lpszText, 
	  LPCSTR lpszFullFileName)
{
	HINSTANCE hMAPI = ::LoadLibrary(L"mapi32.dll");
	LPMAPISENDMAIL lpfnMAPISendMail = 
		(LPMAPISENDMAIL)::GetProcAddress(hMAPI, "MAPISendMail");

	char szDrive[_MAX_DRIVE] = { 0 };
	char szDir[_MAX_DIR] = { 0 };
	char szName[_MAX_FNAME] = { 0 };
	char szExt[_MAX_EXT] = { 0 };
	_splitpath_s(lpszFullFileName, szDrive, szDir, szName, szExt);

	char szFileName[MAX_PATH] = { 0 };
	strcat_s(szFileName, szName);
	strcat_s(szFileName, szExt);

	char szFullFileName[MAX_PATH] = { 0 };
	strcat_s(szFullFileName, lpszFullFileName);

	MapiFileDesc MAPIfile = { 0 };
	ZeroMemory(&MAPIfile, sizeof(MapiFileDesc));
	MAPIfile.nPosition = 0xFFFFFFFF;
	MAPIfile.lpszPathName = szFullFileName;
	MAPIfile.lpszFileName = szFileName;

	char szTo[MAX_PATH] = { 0 };
	strcat_s(szTo, lpszTo);

	char szNameTo[MAX_PATH] = { 0 };
	strcat_s(szNameTo, lpszName);

	MapiRecipDesc recipient = { 0 };
	recipient.ulRecipClass = MAPI_TO;
	recipient.lpszAddress = szTo;
	recipient.lpszName = szNameTo;

	char szSubject[MAX_PATH] = { 0 };
	strcat_s(szSubject, lpszSubject);

	char szText[MAX_PATH] = { 0 };
	strcat_s(szText, lpszText);

	MapiMessage MAPImsg = { 0 };
	MAPImsg.lpszSubject = szSubject;
	MAPImsg.lpRecips = &recipient;
	MAPImsg.nRecipCount = 1;
	MAPImsg.lpszNoteText = szText;
	MAPImsg.nFileCount = 1;
	MAPImsg.lpFiles = &MAPIfile;

	ULONG nSent = lpfnMAPISendMail(0, 0, &MAPImsg, NULL, 0);

	FreeLibrary(hMAPI);
	return (nSent == SUCCESS_SUCCESS || nSent == MAPI_E_USER_ABORT);
}

Open in new window


Logon and Logoff

These examples work, if you have your mail client (Outlook) running. Otherwise MAPISendMail function will fail with MAPI_E_LOGON_FAILURE return code.

Simple MAPI has 2 special functions that are supposed to fix the situation:

1. MAPILogon
2. MAPILogoff

You can test these functions with the following sample:

 
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <mapi.h>

BOOL SendMail(LPCSTR lpszSubject, LPCSTR lpszTo, 
	  LPCSTR lpszName, LPCSTR lpszText);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
	LPWSTR lpCmdLine, int nCmdShow)
{
	SendMail("Subject", "SMTP:someone@somewhere.com", 
			"Name", "Text. No mail client running.");

	return 0;
}

BOOL SendMail(LPCSTR lpszSubject, LPCSTR lpszTo, 
	LPCSTR lpszName, LPCSTR lpszText)
{
	HINSTANCE hMAPI			= NULL;
	LPMAPISENDMAIL lpfnMAPISendMail	= NULL;
	LPMAPILOGON lpfnMAPILogOn		= NULL;
	LPMAPILOGOFF lpfnMAPILogOff	= NULL;

	hMAPI = ::LoadLibrary(L"mapi32.dll");
	lpfnMAPISendMail = 
		(LPMAPISENDMAIL)::GetProcAddress(hMAPI, "MAPISendMail");

	lpfnMAPILogOn = 
		(LPMAPILOGON)::GetProcAddress(hMAPI, "MAPILogon");

	lpfnMAPILogOff = 
		(LPMAPILOGOFF)::GetProcAddress(hMAPI, "MAPILogoff");

	char szTo[MAX_PATH] = { 0 };
	strcat_s(szTo, lpszTo);

	char szName[MAX_PATH] = { 0 };
	strcat_s(szName, lpszName);

	MapiRecipDesc recipient[1] = { 0 };
	recipient[0].ulRecipClass = MAPI_TO;
	recipient[0].lpszAddress = szTo;
	recipient[0].lpszName = szName;

	char szSubject[MAX_PATH] = { 0 };
	strcat_s(szSubject, lpszSubject);

	char szText[MAX_PATH] = { 0 };
	strcat_s(szText, lpszText);

	MapiMessage MAPImsg = { 0 };
	MAPImsg.lpszSubject = szSubject;
	MAPImsg.lpRecips = recipient;
	MAPImsg.nRecipCount = 1;
	MAPImsg.lpszNoteText = szText;

	LHANDLE lhSession;
	lpfnMAPILogOn(0, NULL, NULL, 0, 0, &lhSession);

	ULONG nSent = lpfnMAPISendMail(lhSession, 0, 
		&MAPImsg, MAPI_LOGON_UI | MAPI_DIALOG, 0);

	lpfnMAPILogOff(lhSession, 0, 0, 0);

	FreeLibrary(hMAPI);
	return (nSent == SUCCESS_SUCCESS || nSent == MAPI_E_USER_ABORT);
}

Open in new window


Sumary

In this artcile I showed only 3 MAPI functions:

1. MAPISendMail
2. MAPILogon
3. MAPILogoff

Simple MAPI contains 12 functions that allow for developers to create applications with basic mail functionalities:

1. Log onto the Microsoft Windows mail client.
2. Compose new message, add recipients, resolve recipient names, add attachment, send message.
3. Retrieve and read messages from the inbox.

For more information specific to Simple MAPI read PC MAPI: Simple MAPI Common Technical Questions and Answers

On CodePlex you can download MFCMAPI - Microsoft's published APIs providing access to MAPI.

Disclaimer

The code presented in this article was tested on Microsoft Windows Vista and Outlook 2007.
In one of the MSND artciles, " MAPI Programming Overview",  I found the following note:  "Simple MAPI is no longer supported in Microsoft Outlook 2007. It is still supported by Exchange Server 2003." Instead Microsoft proposes Outlook 2007 MAPI: "Welcome to the Outlook 2007 MAPI Reference"


 
0
Comment
Author:pgnatyuk
1 Comment

Expert Comment

by:bukk2329
please give me step by step solution to create application to " read outlook mail using win32 programming "
0

Featured Post

OWASP: Threats Fundamentals

Learn the top ten threats that are present in modern web-application development and how to protect your business from them.

Join & Write a Comment

This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Please check the video also in regards to recovery of deleted emails from office 365 admin center and through the MFCMAPI tool. I have mentioned each and every step with the proper steps that need to be taken care of.

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month