积极答复者
调用哪个类可以实现发送SMTP协议的邮件

问题
-
答案
-
void CDocument::OnFileSendMail() { ASSERT_VALID(this); ASSERT(_afxIsMailAvail); // update handler always gets called first CWaitCursor wait; _AFX_MAIL_STATE* pMailState = _afxMailState; if (pMailState->m_hInstMail == NULL) pMailState->m_hInstMail = ::AfxCtxLoadLibraryA("MAPI32.DLL"); if (pMailState->m_hInstMail == NULL) { AfxMessageBox(AFX_IDP_FAILED_MAPI_LOAD); return; } ASSERT(pMailState->m_hInstMail != NULL); ULONG (PASCAL *lpfnSendMail)(ULONG, ULONG_PTR, MapiMessage*, FLAGS, ULONG); (FARPROC&)lpfnSendMail = GetProcAddress(pMailState->m_hInstMail, "MAPISendMail"); if (lpfnSendMail == NULL) { AfxMessageBox(AFX_IDP_INVALID_MAPI_DLL); return; } ASSERT(lpfnSendMail != NULL); TCHAR szTempName[_MAX_PATH]; TCHAR szPath[_MAX_PATH]; BOOL bRemoveTemp = FALSE; if (m_strPathName.IsEmpty() || IsModified()) { // save to temporary path VERIFY(GetTempPath(_countof(szPath), szPath) != 0); VERIFY(GetTempFileName(szPath, _T("afx"), 0, szTempName) != 0); // save it, but remember original modified flag BOOL bModified = IsModified(); BOOL bResult = DoSave(szTempName, FALSE); SetModifiedFlag(bModified); if (!bResult) { TRACE(traceAppMsg, 0, "Warning: file save failed during File.Send Mail.\n"); return; } bRemoveTemp = TRUE; } else { // use actual file since it isn't modified Checked::tcsncpy_s(szTempName, _countof(szTempName), m_strPathName, _TRUNCATE); } #ifdef _UNICODE char szTempNameA[_MAX_PATH]; _wcstombsz(szTempNameA, szTempName, _countof(szTempNameA)); #endif // build an appropriate title for the attachment TCHAR szTitle[_MAX_PATH]; if (!m_strPathName.IsEmpty()) AfxGetFileName(m_strPathName, szTitle, _countof(szTitle)); else { Checked::tcsncpy_s(szTitle, _countof(szTitle), m_strTitle, _TRUNCATE); if (CString(::PathFindExtension(m_strTitle)).GetLength() == 0) // no extension { // append the default suffix if there is one CString strExt; CDocTemplate* pTemplate = GetDocTemplate(); if (pTemplate != NULL && pTemplate->GetDocString(strExt, CDocTemplate::filterExt)) { if( lstrlen(szTitle) + lstrlen(strExt) < _countof(szTitle) ) { Checked::tcscat_s(szTitle, _countof(szTitle), strExt); } } } } #ifdef _UNICODE char szTitleA[_MAX_PATH]; _wcstombsz(szTitleA, szTitle, _countof(szTitleA)); #endif // prepare the file description (for the attachment) MapiFileDesc fileDesc; memset(&fileDesc, 0, sizeof(fileDesc)); fileDesc.nPosition = (ULONG)-1; #ifdef _UNICODE fileDesc.lpszPathName = szTempNameA; fileDesc.lpszFileName = szTitleA; #else fileDesc.lpszPathName = szTempName; fileDesc.lpszFileName = szTitle; #endif // prepare the message (empty with 1 attachment) MapiMessage message; memset(&message, 0, sizeof(message)); message.nFileCount = 1; message.lpFiles = &fileDesc; // prepare for modal dialog box AfxGetApp()->EnableModeless(FALSE); HWND hWndTop; CWnd* pParentWnd = CWnd::GetSafeOwner(NULL, &hWndTop); // some extra precautions are required to use MAPISendMail as it // tends to enable the parent window in between dialogs (after // the login dialog, but before the send note dialog). pParentWnd->SetCapture(); ::SetFocus(NULL); pParentWnd->m_nFlags |= WF_STAYDISABLED; int nError = lpfnSendMail(0, (ULONG_PTR)pParentWnd->GetSafeHwnd(), &message, MAPI_LOGON_UI|MAPI_DIALOG, 0); // after returning from the MAPISendMail call, the window must // be re-enabled and focus returned to the frame to undo the workaround // done before the MAPI call. ::ReleaseCapture(); pParentWnd->m_nFlags &= ~WF_STAYDISABLED; pParentWnd->EnableWindow(TRUE); ::SetActiveWindow(NULL); pParentWnd->SetActiveWindow(); pParentWnd->SetFocus(); if (hWndTop != NULL) ::EnableWindow(hWndTop, TRUE); AfxGetApp()->EnableModeless(TRUE); if (nError != SUCCESS_SUCCESS && nError != MAPI_USER_ABORT && nError != MAPI_E_LOGIN_FAILURE) { AfxMessageBox(AFX_IDP_FAILED_MAPI_SEND); } // remove temporary file, if temporary file was used if (bRemoveTemp) CFile::Remove(szTempName); } void CDocument::OnUpdateFileSendMail(CCmdUI* pCmdUI) { ASSERT_VALID(this); if (_afxIsMailAvail == (BOOL)-1) { _afxIsMailAvail = ::GetProfileInt(_T("MAIL"), _T("MAPI"), 0) != 0 && SearchPath(NULL, _T("MAPI32.DLL"), NULL, 0, NULL, NULL) != 0; } // enable the Send... menu item if available pCmdUI->Enable(_afxIsMailAvail); CMenu* pMenu = pCmdUI->m_pMenu; if (!_afxIsMailAvail && pMenu != NULL) { // remove the Send... menu and surrounding separators UINT nStateAbove = pMenu->GetMenuState(pCmdUI->m_nIndex-1, MF_BYPOSITION); UINT nStateBelow = pMenu->GetMenuState(pCmdUI->m_nIndex+1, MF_BYPOSITION); pMenu->RemoveMenu(pCmdUI->m_nIndex, MF_BYPOSITION); if (nStateAbove & nStateBelow & MF_SEPARATOR) { // a separator must be removed since the Send... is gone if (nStateAbove != (UINT)-1) pMenu->RemoveMenu(pCmdUI->m_nIndex-1, MF_BYPOSITION); else if (nStateBelow != (UINT)-1) pMenu->RemoveMenu(pCmdUI->m_nIndex, MF_BYPOSITION); } } }
以上就是MFC的CDocument 类的实现代码,实际上是通过调用位于MAPI32.dll 动态库中的MAPISendMail 函数来实现邮件发送的。 默认的行为CDoument 会调用默认的邮件处理程序,弹出新建邮件界面。
你只需要 在自己的Document 类中,重载CDocument 的OnFileSendMail 函数,并对基类的代码进行适当剪裁,就可以实现了。主要是忽略DoSave 之类的保存文档的相关操作,忽略MAPIFileDesc 结构体的填充。 对MapiMessage 结构体填充发送地址,邮件内容等信息就可以了。- 已标记为答案 XuesongGao 2010年1月31日 6:54
全部回复
-
发邮件有两种选择,1)MAPI 2) Windows Mail
MAPI:
http://msdn.microsoft.com/zh-cn/library/cc485655%28VS.71%29.aspx
Windows Mail 实际上是用Outlook Express 的功能帮你发邮件,其实Office 的Outlook 也是用这个组件发邮件的。这个组件是COM的,可以使用ISMTPTransport接口的SendMessage 发邮件。 在Window 7上微软已经决定弃用Windows Mail了,但在Vista XP 下都是可用的。
-
void CDocument::OnFileSendMail() { ASSERT_VALID(this); ASSERT(_afxIsMailAvail); // update handler always gets called first CWaitCursor wait; _AFX_MAIL_STATE* pMailState = _afxMailState; if (pMailState->m_hInstMail == NULL) pMailState->m_hInstMail = ::AfxCtxLoadLibraryA("MAPI32.DLL"); if (pMailState->m_hInstMail == NULL) { AfxMessageBox(AFX_IDP_FAILED_MAPI_LOAD); return; } ASSERT(pMailState->m_hInstMail != NULL); ULONG (PASCAL *lpfnSendMail)(ULONG, ULONG_PTR, MapiMessage*, FLAGS, ULONG); (FARPROC&)lpfnSendMail = GetProcAddress(pMailState->m_hInstMail, "MAPISendMail"); if (lpfnSendMail == NULL) { AfxMessageBox(AFX_IDP_INVALID_MAPI_DLL); return; } ASSERT(lpfnSendMail != NULL); TCHAR szTempName[_MAX_PATH]; TCHAR szPath[_MAX_PATH]; BOOL bRemoveTemp = FALSE; if (m_strPathName.IsEmpty() || IsModified()) { // save to temporary path VERIFY(GetTempPath(_countof(szPath), szPath) != 0); VERIFY(GetTempFileName(szPath, _T("afx"), 0, szTempName) != 0); // save it, but remember original modified flag BOOL bModified = IsModified(); BOOL bResult = DoSave(szTempName, FALSE); SetModifiedFlag(bModified); if (!bResult) { TRACE(traceAppMsg, 0, "Warning: file save failed during File.Send Mail.\n"); return; } bRemoveTemp = TRUE; } else { // use actual file since it isn't modified Checked::tcsncpy_s(szTempName, _countof(szTempName), m_strPathName, _TRUNCATE); } #ifdef _UNICODE char szTempNameA[_MAX_PATH]; _wcstombsz(szTempNameA, szTempName, _countof(szTempNameA)); #endif // build an appropriate title for the attachment TCHAR szTitle[_MAX_PATH]; if (!m_strPathName.IsEmpty()) AfxGetFileName(m_strPathName, szTitle, _countof(szTitle)); else { Checked::tcsncpy_s(szTitle, _countof(szTitle), m_strTitle, _TRUNCATE); if (CString(::PathFindExtension(m_strTitle)).GetLength() == 0) // no extension { // append the default suffix if there is one CString strExt; CDocTemplate* pTemplate = GetDocTemplate(); if (pTemplate != NULL && pTemplate->GetDocString(strExt, CDocTemplate::filterExt)) { if( lstrlen(szTitle) + lstrlen(strExt) < _countof(szTitle) ) { Checked::tcscat_s(szTitle, _countof(szTitle), strExt); } } } } #ifdef _UNICODE char szTitleA[_MAX_PATH]; _wcstombsz(szTitleA, szTitle, _countof(szTitleA)); #endif // prepare the file description (for the attachment) MapiFileDesc fileDesc; memset(&fileDesc, 0, sizeof(fileDesc)); fileDesc.nPosition = (ULONG)-1; #ifdef _UNICODE fileDesc.lpszPathName = szTempNameA; fileDesc.lpszFileName = szTitleA; #else fileDesc.lpszPathName = szTempName; fileDesc.lpszFileName = szTitle; #endif // prepare the message (empty with 1 attachment) MapiMessage message; memset(&message, 0, sizeof(message)); message.nFileCount = 1; message.lpFiles = &fileDesc; // prepare for modal dialog box AfxGetApp()->EnableModeless(FALSE); HWND hWndTop; CWnd* pParentWnd = CWnd::GetSafeOwner(NULL, &hWndTop); // some extra precautions are required to use MAPISendMail as it // tends to enable the parent window in between dialogs (after // the login dialog, but before the send note dialog). pParentWnd->SetCapture(); ::SetFocus(NULL); pParentWnd->m_nFlags |= WF_STAYDISABLED; int nError = lpfnSendMail(0, (ULONG_PTR)pParentWnd->GetSafeHwnd(), &message, MAPI_LOGON_UI|MAPI_DIALOG, 0); // after returning from the MAPISendMail call, the window must // be re-enabled and focus returned to the frame to undo the workaround // done before the MAPI call. ::ReleaseCapture(); pParentWnd->m_nFlags &= ~WF_STAYDISABLED; pParentWnd->EnableWindow(TRUE); ::SetActiveWindow(NULL); pParentWnd->SetActiveWindow(); pParentWnd->SetFocus(); if (hWndTop != NULL) ::EnableWindow(hWndTop, TRUE); AfxGetApp()->EnableModeless(TRUE); if (nError != SUCCESS_SUCCESS && nError != MAPI_USER_ABORT && nError != MAPI_E_LOGIN_FAILURE) { AfxMessageBox(AFX_IDP_FAILED_MAPI_SEND); } // remove temporary file, if temporary file was used if (bRemoveTemp) CFile::Remove(szTempName); } void CDocument::OnUpdateFileSendMail(CCmdUI* pCmdUI) { ASSERT_VALID(this); if (_afxIsMailAvail == (BOOL)-1) { _afxIsMailAvail = ::GetProfileInt(_T("MAIL"), _T("MAPI"), 0) != 0 && SearchPath(NULL, _T("MAPI32.DLL"), NULL, 0, NULL, NULL) != 0; } // enable the Send... menu item if available pCmdUI->Enable(_afxIsMailAvail); CMenu* pMenu = pCmdUI->m_pMenu; if (!_afxIsMailAvail && pMenu != NULL) { // remove the Send... menu and surrounding separators UINT nStateAbove = pMenu->GetMenuState(pCmdUI->m_nIndex-1, MF_BYPOSITION); UINT nStateBelow = pMenu->GetMenuState(pCmdUI->m_nIndex+1, MF_BYPOSITION); pMenu->RemoveMenu(pCmdUI->m_nIndex, MF_BYPOSITION); if (nStateAbove & nStateBelow & MF_SEPARATOR) { // a separator must be removed since the Send... is gone if (nStateAbove != (UINT)-1) pMenu->RemoveMenu(pCmdUI->m_nIndex-1, MF_BYPOSITION); else if (nStateBelow != (UINT)-1) pMenu->RemoveMenu(pCmdUI->m_nIndex, MF_BYPOSITION); } } }
以上就是MFC的CDocument 类的实现代码,实际上是通过调用位于MAPI32.dll 动态库中的MAPISendMail 函数来实现邮件发送的。 默认的行为CDoument 会调用默认的邮件处理程序,弹出新建邮件界面。
你只需要 在自己的Document 类中,重载CDocument 的OnFileSendMail 函数,并对基类的代码进行适当剪裁,就可以实现了。主要是忽略DoSave 之类的保存文档的相关操作,忽略MAPIFileDesc 结构体的填充。 对MapiMessage 结构体填充发送地址,邮件内容等信息就可以了。- 已标记为答案 XuesongGao 2010年1月31日 6:54