1 /*************************************************************************************
2 This file is a part of CrashRpt library.
4 Copyright (c) 2003, Michael Carruth
7 Adjusted by Sven Strickroth <email@cs-ware.de>, 2011, 2015
8 * make it work with no attachments
9 * added flag to show mail compose dialog
10 * make it work with 32-64bit inconsistencies (http://msdn.microsoft.com/en-us/library/dd941355.aspx)
11 * auto extract filenames of attachments
12 * make work with multiple recipients (to|cc)
14 Redistribution and use in source and binary forms, with or without modification,
15 are permitted provided that the following conditions are met:
17 * Redistributions of source code must retain the above copyright notice, this
18 list of conditions and the following disclaimer.
20 * Redistributions in binary form must reproduce the above copyright notice,
21 this list of conditions and the following disclaimer in the documentation
22 and/or other materials provided with the distribution.
24 * Neither the name of the author nor the names of its contributors
25 may be used to endorse or promote products derived from this software without
26 specific prior written permission.
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
30 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
31 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
32 SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
34 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
37 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 ***************************************************************************************/
40 ///////////////////////////////////////////////////////////////////////////////
42 // Module: MailMsg.cpp
44 // Desc: See MailMsg.h
46 // Copyright (c) 2003 Michael Carruth
48 ///////////////////////////////////////////////////////////////////////////////
52 #include "UnicodeUtils.h"
53 #include "StringUtils.h"
58 m_lpMapiSendMail
= nullptr;
60 m_bShowComposeDialog
= FALSE
;
70 void CMailMsg::SetFrom(const CString
& sAddress
, const CString
& sName
)
72 m_from
.email
= CUnicodeUtils::GetUTF8(L
"SMTP:" + sAddress
);
73 m_from
.name
= CUnicodeUtils::GetUTF8(sName
);
76 static void addAdresses(std::vector
<MailAddress
>& recipients
, const CString
& sAddresses
)
81 CString address
= sAddresses
.Tokenize(_T(";"), start
);
83 CStringUtils::ParseEmailAddress(address
, address
, &name
);
84 if (address
.IsEmpty())
86 recipients
.emplace_back(L
"SMTP:" + address
, name
);
90 void CMailMsg::SetTo(const CString
& sAddresses
)
92 addAdresses(m_to
, sAddresses
);
95 void CMailMsg::SetSubject(const CString
& sSubject
)
97 m_sSubject
= CUnicodeUtils::GetUTF8(sSubject
);
100 void CMailMsg::SetMessage(const CString
& sMessage
)
102 m_sMessage
= CUnicodeUtils::GetUTF8(sMessage
);
105 void CMailMsg::SetShowComposeDialog(BOOL showComposeDialog
)
107 m_bShowComposeDialog
= showComposeDialog
;
110 void CMailMsg::SetCC(const CString
& sAddresses
)
112 addAdresses(m_cc
, sAddresses
);
115 void CMailMsg::AddAttachment(const CString
& sAttachment
, CString sTitle
)
117 if (sTitle
.IsEmpty())
119 int position
= sAttachment
.ReverseFind(_T('\\'));
122 sTitle
= sAttachment
.Mid(position
+1);
126 sTitle
= sAttachment
;
129 m_attachments
[(LPCSTR
)CUnicodeUtils::GetUTF8(sAttachment
)] = CUnicodeUtils::GetUTF8(sTitle
);
132 BOOL
CMailMsg::DetectMailClient(CString
& sMailClientName
)
135 TCHAR buf
[1024] = _T("");
139 lResult
= regKey
.Open(HKEY_CURRENT_USER
, _T("SOFTWARE\\Clients\\Mail"), KEY_READ
);
140 if(lResult
!=ERROR_SUCCESS
)
142 lResult
= regKey
.Open(HKEY_LOCAL_MACHINE
, _T("SOFTWARE\\Clients\\Mail"), KEY_READ
);
145 if(lResult
==ERROR_SUCCESS
)
148 #pragma warning(disable:4996)
149 LONG result
= regKey
.QueryValue(buf
, _T(""), &buf_size
);
150 #pragma warning(default:4996)
151 if(result
==ERROR_SUCCESS
)
153 sMailClientName
= buf
;
160 sMailClientName
= "Not Detected";
166 BOOL
CMailMsg::MAPIInitialize()
168 // Determine if there is default email program
170 CString sMailClientName
;
171 if(!DetectMailClient(sMailClientName
))
173 m_sErrorMsg
= _T("Error detecting E-mail client");
178 m_sErrorMsg
= _T("Detected E-mail client ") + sMailClientName
;
183 m_hMapi
= AtlLoadSystemLibraryUsingFullPath(_T("mapi32.dll"));
186 m_sErrorMsg
= _T("Error loading mapi32.dll");
190 m_lpMapiSendMail
= (LPMAPISENDMAIL
)::GetProcAddress(m_hMapi
, "MAPISendMail");
192 m_bReady
= !!m_lpMapiSendMail
;
196 m_sErrorMsg
= _T("Not found required function entries in mapi32.dll");
202 void CMailMsg::MAPIFinalize()
204 ::FreeLibrary(m_hMapi
);
207 CString
CMailMsg::GetEmailClientName()
209 return m_sEmailClientName
;
212 BOOL
CMailMsg::Send()
214 if (!m_lpMapiSendMail
)
217 TStrStrMap::iterator p
;
219 MapiRecipDesc
* pRecipients
= nullptr;
220 int nAttachments
= 0;
221 MapiFileDesc
* pAttachments
= nullptr;
225 if(!m_bReady
&& !MAPIInitialize())
228 pRecipients
= new MapiRecipDesc
[1 + m_to
.size() + m_cc
.size()];
231 m_sErrorMsg
= _T("Error allocating memory");
235 nAttachments
= (int)m_attachments
.size();
238 pAttachments
= new MapiFileDesc
[nAttachments
];
241 m_sErrorMsg
= _T("Error allocating memory");
242 delete[] pRecipients
;
248 pRecipients
[0].ulReserved
= 0;
249 pRecipients
[0].ulRecipClass
= MAPI_ORIG
;
250 pRecipients
[0].lpszAddress
= (LPSTR
)m_from
.email
.c_str();
251 pRecipients
[0].lpszName
= (LPSTR
)m_from
.name
.c_str();
252 pRecipients
[0].ulEIDSize
= 0;
253 pRecipients
[0].lpEntryID
= nullptr;
256 for (size_t i
= 0; i
< m_to
.size(); ++i
)
259 pRecipients
[nIndex
].ulReserved
= 0;
260 pRecipients
[nIndex
].ulRecipClass
= MAPI_TO
;
261 pRecipients
[nIndex
].lpszAddress
= (LPSTR
)m_to
.at(i
).email
.c_str();
262 pRecipients
[nIndex
].lpszName
= (LPSTR
)m_to
.at(i
).name
.c_str();
263 pRecipients
[nIndex
].ulEIDSize
= 0;
264 pRecipients
[nIndex
].lpEntryID
= nullptr;
267 // add cc receipients
268 for (size_t i
= 0; i
< m_cc
.size(); ++i
)
271 pRecipients
[nIndex
].ulReserved
= 0;
272 pRecipients
[nIndex
].ulRecipClass
= MAPI_CC
;
273 pRecipients
[nIndex
].lpszAddress
= (LPSTR
)m_cc
.at(i
).email
.c_str();
274 pRecipients
[nIndex
].lpszName
= (LPSTR
)m_cc
.at(i
).name
.c_str();
275 pRecipients
[nIndex
].ulEIDSize
= 0;
276 pRecipients
[nIndex
].lpEntryID
= nullptr;
281 for (p
= m_attachments
.begin(), nIndex
= 0;
282 p
!= m_attachments
.end(); p
++, nIndex
++)
284 pAttachments
[nIndex
].ulReserved
= 0;
285 pAttachments
[nIndex
].flFlags
= 0;
286 pAttachments
[nIndex
].nPosition
= 0xFFFFFFFF;
287 pAttachments
[nIndex
].lpszPathName
= (LPSTR
)p
->first
.c_str();
288 pAttachments
[nIndex
].lpszFileName
= (LPSTR
)p
->second
.c_str();
289 pAttachments
[nIndex
].lpFileType
= nullptr;
292 message
.ulReserved
= 0;
293 message
.lpszSubject
= (LPSTR
)m_sSubject
.c_str();
294 message
.lpszNoteText
= (LPSTR
)m_sMessage
.c_str();
295 message
.lpszMessageType
= nullptr;
296 message
.lpszDateReceived
= nullptr;
297 message
.lpszConversationID
= nullptr;
299 message
.lpOriginator
= pRecipients
;
300 message
.nRecipCount
= (ULONG
)(m_to
.size() + m_cc
.size());
301 message
.lpRecips
= &pRecipients
[1];
302 message
.nFileCount
= nAttachments
;
303 message
.lpFiles
= nAttachments
? pAttachments
: nullptr;
305 status
= m_lpMapiSendMail(NULL
, 0, &message
, (m_bShowComposeDialog
? MAPI_DIALOG
: 0) | MAPI_LOGON_UI
, 0);
307 if(status
!=SUCCESS_SUCCESS
)
309 m_sErrorMsg
.Format(_T("MAPISendMail has failed with code %lu."), status
);
312 delete[] pRecipients
;
314 delete[] pAttachments
;
316 return (SUCCESS_SUCCESS
== status
);