Introduction

The CSmtp class allows to send emails from your program. The inspiration to write the CSmtp class was the article: CFastSmtp - A fast and easy SMTP class... I have used the code of CFastSmtp and introduced the following changes:

some bags have been removed (i.e., free memory)

logging in with authentication has been applied (AUTH LOGIN)

sending attachments has been added

error handling has been modified

new headlines from MIME specifications (i.e., X-Priority) have been added

non-blocking mode has been added

exceptions have been used

compatibility with Linux systems has been ensured

Typical scenarios while sending emails

After successful connection to an SMTP server, our client starts the conversation with the remote SMTP server. Each line sent by the client ought to be finished by "\r\n". If you want to know more details, check the References: [2], [3], [4], [5], [6], [7], [8], and [9]. In [2] is described the original SMTP protocol (1982), in [4] is discussed the SMTP extensions for authentication, and the MIME specification is improved in [5]-[9]. Below there are shown typical scenarios while sending e-mails. Example 3 fails because no TLS procedures were implemented in the CSmtp class. If you want to add TLS, see OpenSSL. I have introduced the following notation: S is a remote server, C is our client, and xxx means information censured.

Example 1 - Connecting to smtp.wp.pl and using an incorrect login or password:

Implementation of the CSmtp class

Implementation of the CSmtp class is very similar for Windows and Linux OSs. There is nothing surprising in this, because Windows uses the generally accepted Berkeley sockets application programming interface (API) [10]. The differences are shown in Table 1 (applies only to the CSmtp class implementation).

If non-blocking mode is used, set socket parameters (function: ioctl/ioctlsocket). Check necessarily what returns each function which will be called after ioctl/ioctlsocket (see next section - Using non-blocking mode).

Connect to the remote server (function: connect).

Introduce yourself - EHLO <SP> <domain> <CRLF>.

Send AUTH LOGIN <CRLF> and another command described in the section "Typical scenarios while sending the email" (functions: send, recv).

Finish the conversation with QUIT <CRLF>.

Close connection with remote machine (function: close/closesocket).

In Windows only, free Winsock2 resources (function: WSACleanup).

Using non-blocking mode

In the latest version of the program, I have used a non-blocking connection. There are many strategies to implement the non-blocking mode (i.e., Select model, WSAAsyncSelect model, WSAEventSelect model, or Completion port I/O model). In my code, I have decided to use the Select model. It is not so complicated as other methods, and works efficiently with a basic connection - one client to one server. The advantages of using non-blocking mode are: the program does not suspend if the remote server stops responding, data can be sent in uneven and unequal portions. Disadvantage of this approach is its complexity. After placing the socket in non-blocking mode, the next API calls are immediately closed. Typically, these calls fail with a an error WSAEWOULDBLOCK (Windows) or EINPROGRESS (Linux), which means that the requested operation is not completed so far. Therefore, in non-blocking mode, a lot of attention should be devoted to analyze errors returned by the API functions. In Select model, we are using the select function [11] after calling such API functions as: send, recv, connect, accept, and others. The parameter ndfs in select is ignored in Windows, but in Linux, it is the highest-numbered file descriptor in any of the three sets (fd_set *readfds, fd_set *writefds, fd_set *exceptfds) plus 1. To illustrate the difference between blocking and non-blocking modes, presented here are two ways of connecting to the remote server. For greater legibility, I have only presented versions for Windows (preprocessor directives were omitted).

Author's notes

If you have problems sending an email, use Visual Studio's debugger and analyze the conversation between your SMTP server and the client; perhaps, your server needs a different kind of authentication or doesn't need it at all.

About the Author

Comments and Discussions

I have found some potential resource leaks in the CSmtp class for new[], delete[], fopen, fclose and throw.

It concerns the following class members:

CSmpt::CSmtp()
1) There is no catch for the new exception handler.

CSmpt::Send()
1) A throw can cause memory leaks for FileBuf, FileName, hFile and hSocket.
2) There is no catch for the new exception handler.
3) The calls GetLocalHostName() GetMsgLineText(), ReceiveData(), SendData(), FormatHeader() and
ConnectRemoteServer() can activate a throw.

CSmtp::GetLocalHostname()
1) There is no catch for the new exception handler.

I'm developing a Visual C++ project working with managed code on VS12. Your CSmtp code was compiled as unmanaged. Do you have a version that was compiled under common language runtime support (/CLR)? Alternatively, how do I work with the unmanaged code version?

I finally figured this out and compiled it to work with CLR code. Many thanks for your contribution.

1) Adding a member telling whether we are using auth or not
2) Adding an accessor to set the member
3) Initialize m_bAuth in ctor
4) In the send() function add an "if (m_bAuth)"-statement around the AUTH, USER, PWD commands

Hello, this is working as intended except the attachment. When i add an attachment and try to send the e-mail (the attachment is not bigger than 1kb), the program simply freezes. It is responding though, but it stops, probably doing mail.Send(); and there it just stops and does nothing else. The function never ends (e-mail is not sent and error is not given).
Thank you for all your help.

it's may be a bug,if u send a mail with a attachment,CSmtp may fail when ur app path is defferent with the attatchment,when I trace the code,I find the problem may at line 667 in csmtp.cpp,at here the author may want to open the attatchment file,but he has seperate the file's full path with "\\",the CFile:Open need a full path if the file is not in the directory of the app who opening it!u should add a variable such as strFullpathFile;

I got a very strange error I can't follow.
I'm sending automatic replies with almost static text.
A file path is the only dynamic string in the body.
The entire text length of the body depends on the length of this file path only.
There is no exclamation mark in the text!
But the recipient gets an exclamation mark!
It is always at the same position: 0x03b2

I'm debugging till

int nRet = send(m_hSocket,&pszBuff[dwPosition],dwMax,0);

It's in:

CSmtp::SendCmd(LPTSTR pszCmd)

There is 100% no '!' in pszBuffer.
Nowhere.But there is an '!' at 0x03b2 in the incoming email.

I want add to mail some files(logs). But sometimes this files are not yet created(error logs are created when someone get error Smile | ), this is interrupting sending giving error file not exists. How avoid this? I can find for them and if this file isn't exist, I can create empty files, than send it, but I don't want send unnecessary files. Can you give me example for sending attachments and avoid errors?(just ignore file no exist and send all anyway)

I want add to mail some files(logs). But sometimes this files are not yet created(error logs are created when someone get error ), this is interrupting sending giving error file not exists. How avoid this? I can find for them and if this file isn't exist, I can create empty files, than send it, but I don't want send unnecessary files. Can you give me example for sending attachments and avoid errors?(just ignore file no exist and send all anyway)

I have used this code and able to send mail with username and password. But I have to send mail without username and password. Is this can not be done with this code or if it is then where do i have to change in the code.

Thanks for the feedback. I'm thinking of changing all the conversions from const char* to using the = operator. This seems to be completely acceptable. Can anyone comment on if there is any advantage to the current method using the std::string::insert function instead?

Very nice library. I just have a question. Due to many mail servers using different security features. Do you have to make a socket for each type? How are attachments handled?

I only gave it a 4 due to some problems I see with your code.
- Why do you mix const char* with std::string? Why not just use const std::string& x rather than just mixing them? When you do need to use const char* x just convert it to it via c_str().

- Mixing Linux code with Windows code just makes the source code more cluttered and less maintainable. Why not just push them in their own source implementation then write another source file that does the platform checks?

I consistently get this error
"Server returned error after sending MAIL FROM"
when I runn my application on a Windows Server 2008 R2.
The same application works fine on Windows 7.
Any suggestions?
Any help is appreciated,

There is a later derivative of this project within CodeProject at SMTP Client with SSL/TLS[^].
For this korisk also supplies a solution (see comments on that page) which includes the ability to modify various features, including suppression of authentication.
Unfortunately korisks mods are based on v1.9 but the source is now at 2.0; so it is necessary to merge the differences into 2.0.