SmtpSendManger.cpp
上传用户:weimei12
上传日期:2022-08-11
资源大小:185k
文件大小:14k
源码类别:

Email客户端

开发平台:

Visual C++

  1. #include "StdAfx.h"
  2. #include "MailMessage.h"
  3. #include "SmtpSendManger.h"
  4. #include "MIMEContentAgent.h"
  5. #include "MIMEMessage.h"
  6. #include "MIMECode.h"
  7. #include "Base64.h"
  8. CSmtpSendManger::response_code CSmtpSendManger::s_response_table[] =
  9. {
  10. //Response expected, Error message if we don't get it
  11. { 250, _T( "SMTP server error" ) },// GENERIC_SUCCESS
  12. { 220, _T( "SMTP server not available" ) },// CONNECT_SUCCESS
  13. { 354, _T( "SMTP server not ready for data" ) },// DATA_SUCCESS
  14. { 221, _T( "SMTP server didn't terminate session" ) },// QUIT_SUCCESS
  15. { 334, _T( "Login SMTP server" ) },//AUTH LOGIN
  16. { 235, _T("authentication successfully") },//LOGIN_SUCCESS
  17. { 553, _T("authentication failed") },//LOGIN_FAILED
  18. //List here, not process mow. Maybe different way to use instead of the above error code.
  19. //error code, error description
  20. { 501, _T("Syntax error in parameters or arguments") },
  21. { 502, _T("Command not implemented") },
  22. { 503, _T("Bad sequence of commands") },
  23. { 504, _T("Command parameter not implemented") },
  24. { 211, _T("System status, or system help reply") },
  25. { 214, _T("Help message") },
  26. { 421, _T("<domain> Service not available, closing transmission channel") },
  27. { 251, _T("User not local; will forward to <forward-path>") },
  28. { 450, _T("Requested mail action not taken: mailbox unavailable") },
  29. { 550, _T("Requested action not taken: mailbox unavailable") },
  30. { 451, _T("Requested action aborted: error in processing") },
  31. { 551, _T("User not local; please try <forward-path>") },
  32. { 452, _T("Requested action not taken: insufficient system storage") },
  33. { 552, _T("Requested mail action aborted: exceeded storage allocation") },
  34. { 554, _T("Transaction failed") }
  35. };
  36. CSmtpSendManger::CSmtpSendManger(void)
  37. {
  38. AfxSocketInit();
  39. m_strError = _T("OK");
  40. m_pszResponse_buf = NULL;
  41. m_nRecvTimeout = 50000;
  42. m_nSendTimeout = 50000;
  43. m_bValidate = TRUE;
  44. }
  45. CSmtpSendManger::~CSmtpSendManger(void)
  46. {
  47. Disconnect();
  48. }
  49. ///<summary>
  50. ///   send the mail
  51. ///</summary>
  52. HRESULT CSmtpSendManger::SendMailMessage(const CString& strRcs, 
  53.  const CString& strCCRcs, 
  54.  const CString& strBCCRcs,
  55.  const CString& strSubject, 
  56.  const CString& strContent,
  57.  const CStringArray& strAttachFiles)
  58. {
  59. //construct the mail 
  60. CMIMEMessage msgToSend;
  61. msgToSend.SetInfo(m_strSendMail, strSubject, strContent, m_strUserName, m_strPassword);
  62. msgToSend.AddMultipleRecipients(strRcs);
  63. msgToSend.AddMultipleRecipients(strCCRcs, CMailMessage::CC);
  64. msgToSend.AddMultipleRecipients(strBCCRcs, CMailMessage::BCC);
  65. int i = 0;
  66. for (; i < strAttachFiles.GetSize(); i++)
  67. {
  68. msgToSend.AddMIMEPart(strAttachFiles[i]);
  69. }
  70. if(msgToSend.GetNumRecipients() == 0)
  71. {
  72. m_strError = _T("No Recipients");
  73. return HRESULT_FAIL;
  74. }
  75. msgToSend.FormatMessage();
  76. //start the transmission
  77. if (!Connect())
  78. {
  79. return HRESULT_FAIL;
  80. }
  81. if (!CmdHelo(EXTEND_SMTP))
  82. {
  83. Disconnect();
  84. return HRESULT_FAIL;
  85. }
  86. if (m_bValidate)
  87. {
  88. if (!CmdAuthLogin())
  89. {
  90. Disconnect();
  91. return HRESULT_FAIL;
  92. }
  93. }
  94. if (!CmdMailFrom())
  95. {
  96. Disconnect();
  97. return HRESULT_FAIL;
  98. }
  99. if (!AddMultiRecipient(&msgToSend))
  100. {
  101. Disconnect();
  102. return HRESULT_FAIL;
  103. }
  104. if (!CmdData(&msgToSend))
  105. {
  106. Disconnect();
  107. return HRESULT_FAIL;
  108. }
  109. if (!Disconnect())
  110. {
  111. return HRESULT_FAIL;
  112. }
  113. return HRESULT_SUCCESS;
  114. }
  115. ///<summary>
  116. ///   set the user name
  117. ///</summary>
  118. void CSmtpSendManger::SetUserName(const CString& strUserName)
  119. {
  120. m_strUserName = strUserName;
  121. }
  122. ///<summary>
  123. ///   set the password
  124. ///</summary>
  125. void CSmtpSendManger::SetPassword(const CString& strPassword)
  126. {
  127. m_strPassword = strPassword;
  128. }
  129. ///<summary>
  130. ///   set the Smtp server address
  131. ///</summary>
  132. void CSmtpSendManger::SetSmtpServer(const CString& strSmtpServer)
  133. {
  134. m_strSmtpServer = strSmtpServer;
  135. }
  136. ///<summary>
  137. ///   set the sender address
  138. ///</summary>
  139. void CSmtpSendManger::SetSendMail(const CString& strSendMail)
  140. {
  141. m_strSendMail = strSendMail;
  142. }
  143. ///<summary>
  144. ///   set whether to validate the identity
  145. ///</summary>
  146. void CSmtpSendManger::SetValidate(IN BOOL bValidate)
  147. {
  148. m_bValidate = bValidate;
  149. }
  150. ///<summary>
  151. ///   get the last error description
  152. ///</summary>
  153. CString CSmtpSendManger::GetLastErrorMsg()
  154. {
  155. return m_strError;
  156. }
  157. BOOL CSmtpSendManger::Connect()
  158. {
  159. //Allocate memory for receiving, and the memory will be deleted in Disconnect();
  160. m_pszResponse_buf = new char[RESPONSE_BUFFER_SIZE];
  161. if(m_pszResponse_buf == NULL)
  162. {
  163. m_strError = _T("Not enough memory");
  164. return FALSE;
  165. }
  166. memset(m_pszResponse_buf, 0, sizeof(RESPONSE_BUFFER_SIZE));
  167. //Create socket, and set corresponding parameters
  168. if(!m_wsSMTPServer.Create())
  169. {
  170. m_strError = _T("Unable to create the socket.");
  171. delete m_pszResponse_buf;
  172. m_pszResponse_buf = NULL;
  173. return FALSE;
  174. }
  175. if (!SetNetParams())
  176. {
  177. return FALSE;
  178. }
  179. //Connect the server
  180. if(!m_wsSMTPServer.Connect(m_strSmtpServer, SMTP_PORT))
  181. {
  182. m_strError = _T("Unable to connect to server");
  183. m_wsSMTPServer.Close();
  184. delete m_pszResponse_buf;
  185. m_pszResponse_buf = NULL;
  186. return FALSE;
  187. }
  188. if(!CheckResponse(CONNECT_SUCCESS))
  189. {
  190. m_strError = _T("Server didn't respond.");
  191. m_wsSMTPServer.Close();
  192. delete m_pszResponse_buf;
  193. m_pszResponse_buf = NULL;
  194. return FALSE;
  195. }
  196. return TRUE;
  197. }
  198. BOOL CSmtpSendManger::Disconnect()
  199. {
  200. CmdQuit();
  201. m_wsSMTPServer.Close();
  202. if(m_pszResponse_buf != NULL)
  203. {
  204. delete[] m_pszResponse_buf;
  205. m_pszResponse_buf = NULL;
  206. }
  207. return TRUE;
  208. }
  209. ///<summary>
  210. ///   identify the sender to the receiver
  211. ///</summary>
  212. BOOL CSmtpSendManger::CmdHelo(int nType /* = ORIGIN_SMTP */)
  213. {
  214. char szLocal_host[_MAX_PATH] = {0};
  215. gethostname(szLocal_host, _MAX_PATH);
  216. CString strHello;
  217. if (ORIGIN_SMTP == nType)
  218. {
  219. strHello.Format("HELO %srn", szLocal_host);
  220. }
  221. else if (EXTEND_SMTP == nType)
  222. {
  223. strHello.Format("EHLO %srn", szLocal_host);
  224. }
  225. m_wsSMTPServer.Send(strHello, strHello.GetLength());
  226. if(!CheckResponse(GENERIC_SUCCESS))
  227. {
  228. m_wsSMTPServer.Close();
  229. delete m_pszResponse_buf;
  230. m_pszResponse_buf = NULL;
  231. return FALSE;
  232. }
  233. return TRUE;
  234. }
  235. ///<summary>
  236. ///   initiate a mail transaction
  237. ///</summary>
  238. BOOL CSmtpSendManger::CmdMailFrom()
  239. {
  240. CString strCmdFrom;
  241. strCmdFrom.Format("MAIL From: <%s>rn", m_strSendMail);
  242. m_wsSMTPServer.Send(strCmdFrom, strCmdFrom.GetLength());
  243. if(!CheckResponse(GENERIC_SUCCESS))
  244. {
  245. return FALSE;
  246. }
  247. return TRUE;
  248. }
  249. ///<summary>
  250. ///   identify the recipient
  251. ///</summary>
  252. BOOL CSmtpSendManger::CmdRcptTo(const CString& strTo)
  253. {
  254. CString strCmdTo;
  255. strCmdTo.Format("RCPT TO: <%s>rn", strTo);
  256. m_wsSMTPServer.Send(strCmdTo, strCmdTo.GetLength());
  257. if(!CheckResponse(GENERIC_SUCCESS))
  258. {
  259. return FALSE;
  260. }
  261. return TRUE;
  262. }
  263. ///<summary>
  264. ///   transmit data without any encoding mechanisms
  265. ///</summary>
  266. BOOL CSmtpSendManger::CmdData(CMailMessage* pMsg)
  267. {
  268. ASSERT(pMsg != NULL);
  269. if (NULL == pMsg)
  270. {
  271. return FALSE;
  272. }
  273. CString strTemp;
  274. // Send the DATA command
  275. strTemp = "DATArn";
  276. m_wsSMTPServer.Send(strTemp, strTemp.GetLength());
  277. if(!CheckResponse(DATA_SUCCESS))
  278. {
  279. return FALSE;
  280. }
  281. // Send the header
  282. m_wsSMTPServer.Send(pMsg->GetMailHeader(), pMsg->GetMailHeader().GetLength());
  283. // Send the body
  284. strTemp = CookBody(pMsg);
  285. m_wsSMTPServer.Send(strTemp, strTemp.GetLength());
  286. // Signal end of data
  287. strTemp = "rn.rn";
  288. m_wsSMTPServer.Send(strTemp, strTemp.GetLength());
  289. if(!CheckResponse(GENERIC_SUCCESS))
  290. {
  291. return FALSE;
  292. }
  293. return TRUE;
  294. }
  295. ///<summary>
  296. ///   confirm a user
  297. ///</summary>
  298. BOOL CSmtpSendManger::CmdVrfy(const CString& str)
  299. {
  300. CString strCmd;
  301. strCmd.Format("VRFY %srn", str);
  302. m_wsSMTPServer.Send(strCmd, strCmd.GetLength());
  303. if(!CheckResponse(GENERIC_SUCCESS))
  304. {
  305. return FALSE;
  306. }
  307. return TRUE;
  308. }
  309. ///<summary>
  310. ///   confirm a mailing list
  311. ///</summary>
  312. BOOL CSmtpSendManger::CmdExpn(const CString& strList)
  313. {
  314. CString strCmd;
  315. strCmd.Format("EXPN %srn", strList);
  316. m_wsSMTPServer.Send(strCmd, strCmd.GetLength());
  317. if(!CheckResponse(GENERIC_SUCCESS))
  318. {
  319. return FALSE;
  320. }
  321. return TRUE;
  322. }
  323. ///<summary>
  324. ///   ask the receiver to send helpful information
  325. ///</summary>
  326. BOOL CSmtpSendManger::CmdHelp(vector<CString>& strCmdList)
  327. {
  328. CString strCmd;
  329. strCmd = "HELPrn";
  330. m_wsSMTPServer.Send(strCmd, strCmd.GetLength());
  331. //Receive the response
  332. int nLen = 0 ;
  333. Sleep(300); 
  334. if( (nLen = m_wsSMTPServer.Receive(m_pszResponse_buf, RESPONSE_BUFFER_SIZE)) == SOCKET_ERROR)
  335. {
  336. m_strError = _T("Socket Error");
  337. return FALSE;
  338. }
  339. m_pszResponse_buf[nLen] = '';
  340. CString strResponse;
  341. strResponse = m_pszResponse_buf;
  342. TRACE("receive: %sn", strResponse);
  343. //parse the response
  344. if (strResponse.Find("rn") <= 0)
  345. {
  346. m_strError = _T("Response Error");
  347. return FALSE;
  348. }
  349. strResponse = strResponse.Right(strResponse.GetLength() - strResponse.Find("rn") - 6);//4 = strlen("rn214 ")
  350. while (strResponse.Find(" ") > 0)
  351. {
  352. strCmdList.push_back(strResponse.Left(strResponse.Find(" ")));
  353. strResponse = strResponse.Right(strResponse.GetLength() - strResponse.Find(" ") - 1);
  354. }
  355. strCmdList.push_back(strResponse);//the last cmd
  356. return TRUE;
  357. }
  358. ///<summary>
  359. ///   no action other than that the receiver send an OK reply
  360. ///</summary>
  361. BOOL CSmtpSendManger::CmdNoop()
  362. {
  363. CString strCmd;
  364. strCmd = "NOOPrn";
  365. m_wsSMTPServer.Send(strCmd, strCmd.GetLength());
  366. if(!CheckResponse(GENERIC_SUCCESS))
  367. {
  368. return FALSE;
  369. }
  370. return TRUE;
  371. }
  372. ///<summary>
  373. ///   close the transmission
  374. ///</summary>
  375. BOOL CSmtpSendManger::CmdQuit()
  376. {
  377. CString strCmd;
  378. strCmd = "QUITrn";
  379. m_wsSMTPServer.Send(strCmd, strCmd.GetLength());
  380. if(!CheckResponse(QUIT_SUCCESS))
  381. {
  382. return FALSE;
  383. }
  384. return TRUE;
  385. }
  386. ///<summary>
  387. ///   cancel the current transaction
  388. ///</summary>
  389. BOOL CSmtpSendManger::CmdRSET()
  390. {
  391. CString strCmd;
  392. strCmd  = "RSETrn";
  393. m_wsSMTPServer.Send(strCmd, strCmd.GetLength());
  394. if(!CheckResponse(GENERIC_SUCCESS))
  395. {
  396. return FALSE;
  397. }
  398. return TRUE;
  399. }
  400. ///<summary>
  401. ///   verify the user
  402. ///</summary>
  403. BOOL CSmtpSendManger::CmdAuthLogin()
  404. {
  405. CString strVerify;
  406. // Send the verify command
  407. strVerify.Format("AUTH LOGINrn") ;
  408. m_wsSMTPServer.Send(strVerify, strVerify.GetLength());
  409. if(!CheckResponse(AUTH_LOGIN))
  410. {
  411. return FALSE;
  412. }
  413. // Send the username
  414. CString strUserName;
  415. strUserName.Format(m_strUserName);
  416. CBase64 base64;
  417. strUserName = base64.Encode(strUserName, strUserName.GetLength());
  418. strUserName += "rn" ;
  419. m_wsSMTPServer.Send(strUserName, strUserName.GetLength());
  420. if(!CheckResponse(AUTH_LOGIN))
  421. {
  422. return FALSE;
  423. }
  424. //Send the password
  425. CString strPassword;
  426. strPassword.Format(m_strPassword);
  427. strPassword = base64.Encode(strPassword, strPassword.GetLength());
  428. strPassword += "rn";
  429. m_wsSMTPServer.Send(strPassword, strPassword.GetLength());
  430. if(!CheckResponse(LOGIN_SUCCESS))
  431. {
  432. return FALSE;
  433. }
  434. return TRUE;
  435. }
  436. ///<summary>
  437. ///   transmit data encoded with base64
  438. ///</summary>
  439. BOOL CSmtpSendManger::AddMultiRecipient(CMailMessage * pMsg)
  440. {
  441. ASSERT(pMsg != NULL);
  442. if (NULL == pMsg)
  443. {
  444. return FALSE;
  445. }
  446. CString strTemp;
  447. CString strEmail;
  448. // Send RCPT commands (one for each recipient)
  449. //the primary recipients
  450. int i = 0;
  451. for(; i < pMsg->GetNumRecipients(); i++)
  452. {
  453. pMsg->GetRecipient(strEmail, strTemp, i);
  454. CmdRcptTo(strEmail);
  455. }
  456. //the  secondary recipients 
  457. for(i = 0; i < pMsg->GetNumRecipients(CMailMessage::CC); i++)
  458. {
  459. pMsg->GetRecipient(strEmail, strTemp, i, CMailMessage::CC);
  460. CmdRcptTo(strEmail);
  461. }
  462. //additional  recipients  
  463. for(i = 0; i < pMsg->GetNumRecipients(CMailMessage::BCC); i++)
  464. {
  465. pMsg->GetRecipient(strEmail, strTemp, i, CMailMessage::BCC);
  466. CmdRcptTo(strEmail);
  467. }
  468. return TRUE;
  469. }
  470. ///<summary>
  471. ///   set socket parameters
  472. ///</summary>
  473. BOOL CSmtpSendManger::SetNetParams()
  474. {
  475. //off TIME_WAIT
  476. struct linger zeroLinger;
  477. zeroLinger.l_onoff = 1;
  478. zeroLinger.l_linger = 0;
  479. if(!m_wsSMTPServer.SetSockOpt(SO_LINGER, (const char *)&zeroLinger
  480. ,sizeof(zeroLinger)))
  481. {
  482. m_strError = _T("Unable to off time_wait.");
  483. delete m_pszResponse_buf;
  484. m_pszResponse_buf = NULL;
  485. return FALSE;
  486. }
  487. //set receive timeout
  488. if(!m_wsSMTPServer.SetSockOpt(SO_RCVTIMEO, (const char *)&m_nRecvTimeout
  489. ,sizeof(m_nRecvTimeout)))
  490. {
  491. m_strError = _T("Unable to set receive timeout.");
  492. delete m_pszResponse_buf;
  493. m_pszResponse_buf = NULL;
  494. return FALSE;
  495. }
  496. //set send timeout
  497. if(!m_wsSMTPServer.SetSockOpt(SO_SNDTIMEO, (const char *)&m_nSendTimeout
  498. ,sizeof(m_nSendTimeout)))
  499. {
  500. m_strError = _T("Unable to set send timeout.");
  501. delete m_pszResponse_buf;
  502. m_pszResponse_buf = NULL;
  503. return FALSE;
  504. }
  505. return TRUE;
  506. }
  507. ///<summary>
  508. ///   handle the periods in the message body 
  509. ///</summary>
  510. CString CSmtpSendManger::CookBody(CMailMessage * pMsg)
  511. {
  512. CString strTemp;
  513. ASSERT(pMsg != NULL);
  514. if (NULL == pMsg)
  515. {
  516. return strTemp;
  517. }
  518. CString strCooked = "";
  519. LPTSTR pszBad = "rn.rn";
  520. LPTSTR pszGood = "rn..rn";
  521. int nPos = 0;
  522. int nStart = 0;
  523. int nBadLength = (int)strlen(pszBad);
  524. strTemp = pMsg->GetMailBody();
  525. if(strTemp.Left(3) == ".rn")
  526. {
  527. strTemp = "." + strTemp;
  528. }
  529. while((nPos = strTemp.Find(pszBad)) > -1)
  530. {
  531. strCooked = strTemp.Mid(nStart, nPos);
  532. strCooked += pszGood;
  533. strTemp = strCooked + strTemp.Right(strTemp.GetLength() - (nPos + nBadLength));
  534. }
  535. return strTemp;
  536. }
  537. BOOL CSmtpSendManger::CheckResponse(UINT nResponse_expected)
  538. {
  539. ASSERT(nResponse_expected >= GENERIC_SUCCESS);
  540. ASSERT(nResponse_expected < LAST_RESPONSE);
  541. CString strResponse;
  542. UINT nResponse = LAST_RESPONSE;
  543. response_code* pResp = NULL;
  544. //Receive the response
  545. int nLen = 0 ;
  546. Sleep(300); 
  547. if( (nLen = m_wsSMTPServer.Receive(m_pszResponse_buf, RESPONSE_BUFFER_SIZE)) == SOCKET_ERROR)
  548. {
  549. m_strError = _T("Socket Error");
  550. return FALSE;
  551. }
  552. m_pszResponse_buf[nLen] = '';
  553. strResponse = m_pszResponse_buf;
  554. TRACE("receive: %sn", strResponse);
  555. //parse the response
  556. sscanf_s(strResponse.Left(3), "%d", &nResponse);
  557. pResp = &s_response_table[nResponse_expected];
  558. if(nResponse != pResp->nResponse)
  559. {
  560. m_strError.Format(_T("%d:%s"), nResponse, pResp->pszMessage);
  561. return FALSE;
  562. }
  563. return TRUE;
  564. }