Sending Email with MAPI

AID: 1820
  • Status: Published

4135 points

  • Bypgnatyuk
  • TypeTips/Tricks
  • Posted on2009-10-21 at 07:13:12
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;
}
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:

Select allOpen 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);
}
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:

Select allOpen 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");
                                    
1:
2:
3:

Select allOpen 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;
                                    
1:
2:
3:
4:
5:

Select allOpen 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;
                                    
1:
2:
3:
4:

Select allOpen 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);
                                    
1:

Select allOpen 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);
}
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:

Select allOpen 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);
}
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:

Select allOpen 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"



Asked On
2009-10-21 at 07:13:12ID1820
Tags

Win32

,

MAPI

,

MAPISendMail

,

ShellExecute

Topic

Windows Programming

Views
2866

Comments

Add your Comment

Please Sign up or Log in to comment on this article.

Join Experts Exchange Today

Gain Access to all our Tech Resources

Get personalized answers

Ask unlimited questions

Access Proven Solutions

Search 3.2 million solutions

Read In-Depth How-To Guides

1000+ articles, demos, & tips

Watch Step by Step Tutorials

Learn direct from top tech pros

And Much More!

Your complete tech resource

See Plans and Pricing

30-day free trial. Register in 60 seconds.

Loading Advertisement...

Top Win OS Dev Experts

  1. DanRollins

    17,145

    90 points yesterday

    Profile
    Rank: Genius
  2. jkr

    7,800

    0 points yesterday

    Profile
    Rank: Savant
  3. sarabande

    5,000

    0 points yesterday

    Profile
    Rank: Sage
  4. sinisav

    4,000

    0 points yesterday

    Profile
    Rank: Master
  5. Zoppo

    3,500

    0 points yesterday

    Profile
    Rank: Genius
  6. burrcm

    2,800

    0 points yesterday

    Profile
    Rank: Genius
  7. DTHConsulting

    2,000

    0 points yesterday

    Profile
    Rank: Guru
  8. Geert_Gruwez

    2,000

    0 points yesterday

    Profile
    Rank: Genius
  9. ImaCircularSaw

    2,000

    0 points yesterday

    Profile
    Rank: Guru
  10. Geisrud

    2,000

    0 points yesterday

    Profile
    Rank: Guru
  11. Run5k

    2,000

    0 points yesterday

    Profile
    Rank: Genius
  12. ShareefHuddle

    2,000

    0 points yesterday

    Profile
    Rank: Guru
  13. tampnic

    2,000

    0 points yesterday

    Profile
    Rank: Master
  14. pgnatyuk

    1,960

    20 points yesterday

    Profile
    Rank: Genius
  15. Thommy

    1,800

    0 points yesterday

    Profile
    Rank: Wizard
  16. mrwad99

    1,800

    0 points yesterday

    Profile
    Rank: Wizard
  17. momi_sabag

    1,800

    1,800 points yesterday

    Profile
    Rank: Genius
  18. TommySzalapski

    1,600

    0 points yesterday

    Profile
    Rank: Genius
  19. ve3ofa

    1,300

    1,300 points yesterday

    Profile
    Rank: Genius
  20. cpkilekofp

    1,300

    1,300 points yesterday

    Profile
    Rank: Sage
  21. Darr247

    1,000

    0 points yesterday

    Profile
    Rank: Genius
  22. thinkpads_user

    1,000

    0 points yesterday

    Profile
    Rank: Genius
  23. matrixnz

    999

    0 points yesterday

    Profile
    Rank: Genius
  24. joshbula

    900

    0 points yesterday

    Profile
    Rank: Master
  25. adminnrg

    750

    0 points yesterday

    Profile

Hall Of Fame