IntroductionIn 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 ShellExecuteIf 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 MAPIIf 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.co
m" 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:
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 LogoffThese 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.
MAPILogon2.
MAPILogoffYou 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
SumaryIn 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 AnswersOn
CodePlex you can download
MFCMAPI - Microsoft's published APIs providing access to MAPI.
DisclaimerThe 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"