Introduction
This application initially was based on an Open Source sample NetManager V1.1 by Petr Stejskal. I used it to explore both MFC and Internet/Networking (email in particular). Email clients nowadays are mostly replaced by Web based email services, but I think this code sample can be useful for programmers studying Internet protocols. This is a relatively simple MFC program to check for email messages on multiple POP accounts. The application was upgraded from Visual C++ 6.0 to VC++ 2008.
Background
To send email, the SMTP (Simple Mail Transfer Protocol) protocol is used. An email message consists of two parts: header and body (+ optional attachment). For ASCII based alphabets, the body (text) is sent non encoded (7-bit ASCII). For non-ASCII data (languages outside the Latin alphabet), encoding is used: the MIME specification lists two binary-to-text encoding schemes quoted-printable for text and base64 for binary attachments. Two protocols are mostly used to retrieve email from a remote server over a TCP/IP connection:
- Internet message access protocol (IMAP);
- Post Office Protocol (POP).
Email clients and mail servers usually support both protocols.
Using the code
By writing this code, I got some practice in MFC, but mostly explored the coding of Internet protocols. Thus, the code is a mix of MFC and C++ classes with some C and Win32 API functions. Every time, I simply used what I thought was best applicable for a task to be solved. For implementation of the POP3 protocol, I adapted the CPop
class by Robert E. Peters that is an update from the POP3 protocol wrapper class written by Asif Rasheed. The code is well commented and should be clear to people with an MFC and Win32 background.
May be of some interest is a function to receive email. On a slow internet connection (such as dial-up), the transmission can get stuck with the program hanging. So, I added a bit of multithreading to the implementation to be able to interrupt the transmission (to close the socket) from the worker thread in such situations. Every time the transmission begins, you can stop it from the message box window shown. Here is the corresponding code (with some omissions):
void CMailPop3::OnReceive()
{
CThreadInfo m_CThreadInfo;
int nItem = -1;
while((nItem = m_Servers.GetNextItem(nItem, LVNI_SELECTED)) != -1)
{
m_CThreadInfo.m_Pop3Comm.SetHost(m_aAccounts[nItem].sServer);
csMailAccount =m_aAccounts[nItem].sServer;
m_CThreadInfo.m_Pop3Comm.SetPort(m_aAccounts[nItem].nPort);
m_CThreadInfo.m_Pop3Comm.SetUser(m_aAccounts[nItem].sUsername);
userName = m_aAccounts[nItem].sUsername;
m_CThreadInfo.m_Pop3Comm.SetPassword(m_aAccounts[nItem].sPassword);
if(!m_CThreadInfo.m_Pop3Comm.Connect())
{
AfxMessageBox(m_CThreadInfo.m_Pop3Comm.GetErrorMessage());
return;
}
nSocketClosed=0;
AfxBeginThread(ThreadProc, &m_CThreadInfo);
if(!m_CThreadInfo.m_Pop3Comm.Statistics())
{
AfxMessageBox(m_CThreadInfo.m_Pop3Comm.GetErrorMessage());
return;
}
m_Mails.DeleteAllItems(); nMailNum = m_CThreadInfo.m_Pop3Comm.GetNumberOfMails();
int nMsgSize;
csFileName =csMailAccount + (".dat");
ofstream outfile(csFileName,ios::out, ios::app);
for(nItem = 0; nItem <nMailNum; nItem++)
{
m_CThreadInfo.m_Pop3Comm.List();
if ((nMailNum % 2) == 0) {
nMsgSize=m_CThreadInfo.m_Pop3Comm.GetMessageSize(nItem);
}
else nMsgSize=m_CThreadInfo.m_Pop3Comm.GetMessageSize(nItem+1);
m_CThreadInfo.m_Pop3Comm.GetTop(nItem+1,nMsgSize);
m_Mails.InsertItem(nItem, csMailAccount);
if (m_CThreadInfo.m_Pop3Comm.t_Attachment == "text/plain;")
{
m_CThreadInfo.m_Pop3Comm.t_Attachment = "";
}
if (nSocketClosed ==0)
{
m_Mails.SetItemText(nItem, 1, m_CThreadInfo.m_Pop3Comm.t_Attachment);
m_Mails.SetItemText(nItem, 2, m_CThreadInfo.m_Pop3Comm.t_From);
m_Mails.SetItemText(nItem, 3, m_CThreadInfo.m_Pop3Comm.t_Subject);
m_Mails.SetItemText(nItem, 4, m_CThreadInfo.m_Pop3Comm.t_Date);
}
else {
m_Mails.DeleteAllItems(); }
m_CThreadInfo.m_Pop3Comm.Retrieve(nItem+1);
m_CThreadInfo.m_Pop3Comm.Disconnect();
PostThreadMessage(nThreadID, WM_QUIT, 0, 0);
Sleep(0);
PostThreadMessage(nThreadID, WM_QUIT, 0, 0);
} }
The application
The application has a very simple user friendly interface:
The features of the email check program are limited by the purpose of the code sample:
- It can read only ASCII (Latin alphabet) email messages from multiple POP accounts.
- The messages are simply output in an Edit Control and a file.
- It can receive attachments but they have to be cut out of the message and decoded by an external base64 decoding application or using an online service.
- Text in languages outside ASCII have to be cut out of the message and decoded by an external quoted printable decoding application or using an online service.
References
History
- 04.2009 - Built in Visual C++ 6.0.
- 04.2011 - Upgraded to Visual C++ 2008.