|
|
Comments and Discussions
|
|
 |

|
how to send email via a proxy?
does it have the setproxy function?
|
|
|
|

|
Hi,
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.
thank you
|
|
|
|

|
I got an error saying server returned error after sending DATA.
I used the program a lot and its awesome but now suddenly I have this error message. Can you please tell me how to solve this or what is wrong?
|
|
|
|

|
It's a good article,but for me it have some problems: 1.If the mail content have chinese word,the display may be wrong for some email receivers. 2.If you add the support for send html content,it will be great. 3.The previous api SetMessageBody() should keep so I can add all text content once.
|
|
|
|

|
Hello,
I am not able to make it work for Windows 7 and Vista, i receive no mail,but it work great on Windows XP, any one had this problem?
I am using GetPrivateProfileString to get information from a ini file to use the smtp client.
ex: mail.SetLogin(VALUEFROM_ini_file);
|
|
|
|

|
Hello,
In a non SSL, non TLS environment how do you "login" with no password (can't seem to skip using mail.SetPassword)
or is just not possible with this code the way it is written?
thank you
|
|
|
|
|

|
The code does this:
strcat(SendBuf,&FileName[Attachments[FileId].find_last_of("\\") + 1]);
But in Linux, the path separator is "/"....
|
|
|
|

|
Great point. Is there better solution than:
for(FileId=0;FileId<Attachments.size();FileId++)
{
strcpy(FileName,Attachments[FileId].c_str());
sprintf(SendBuf,"--%s\r\n",BOUNDARY_TEXT);
strcat(SendBuf,"Content-Type: application/x-msdownload; name=\"");
#ifndef LINUX
strcat(SendBuf,&FileName[Attachments[FileId].find_last_of("\\") + 1]);
#else
strcat(SendBuf,&FileName[Attachments[FileId].find_last_of("/") + 1]);
#endif
strcat(SendBuf,"\"\r\n");
strcat(SendBuf,"Content-Transfer-Encoding: base64\r\n");
strcat(SendBuf,"Content-Disposition: attachment; filename=\"");
#ifndef LINUX
strcat(SendBuf,&FileName[Attachments[FileId].find_last_of("\\") + 1]);
#else
strcat(SendBuf,&FileName[Attachments[FileId].find_last_of("/") + 1]);
#endif
strcat(SendBuf,"\"\r\n");
strcat(SendBuf,"\r\n");
.
.
.
|
|
|
|

|
uSTL doesn't like it (blows up w/ an assert) when you set an xstring by doing this:
m_stdstring = m_stdstring.insert(0, newstring);
This kicks in a constructor but works:
m_stdstring = newstring;
If you're using it on an embedded system, you can't throw exceptions (they take up a lot of code space so they're generally disabled). You need to do the old C technique of returning error codes...
|
|
|
|

|
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?
|
|
|
|

|
thanks for your contribution...well done
|
|
|
|

|
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?
#ifdef (Windows)
return WindowsFunction();
#else
return LinuxMacFunction();
#endif
|
|
|
|

|
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,
Thank you,
Gene
|
|
|
|

|
1st of all nice work...
your code could be a little prettier but work is done.
const char* CSmtp::GetLocalHostName() const
{
char* str = NULL;
if((str = new char[255]) == NULL)
throw ECSmtp(ECSmtp::LACK_OF_MEMORY);
if(gethostname(str,255) == SOCKET_ERROR)
{
delete[] str;
throw ECSmtp(ECSmtp::WSA_HOSTNAME);
}
delete[] str;
return m_sLocalHostName.c_str();
}
instead i use this (so i can use it from domain):
void CSmtp::SetLocalHostName(const char *sLocalHostName)
{
m_sLocalHostName.erase();
m_sLocalHostName.insert(0,sLocalHostName);
}
const char* CSmtp::GetLocalHostName() const
{
return m_sLocalHostName.c_str();
}
and from outside setting the comp name
...
mail.SetLocalHostName( GetComputerName() ); ...
for server that does not need authentication u must skip the authentication part..
so I use bool param to skip it
like this:
void CSmtp::Send(BOOL bAuthRequired)
{
unsigned int i,rcpt_count,res,FileId;
char *FileBuf = NULL, *FileName = NULL;
FILE* hFile = NULL;
unsigned long int FileSize,TotalSize,MsgPart;
bool bAccepted;
if( (hSocket = ConnectRemoteServer(m_sSMTPSrvName.c_str(), m_iSMTPSrvPort)) == INVALID_SOCKET )
throw ECSmtp(ECSmtp::WSA_INVALID_SOCKET);
bAccepted = false;
do
{
ReceiveData();
switch(SmtpXYZdigits())
{
case 220:
bAccepted = true;
break;
default:
throw ECSmtp(ECSmtp::SERVER_NOT_READY);
}
}while(!bAccepted);
sprintf(SendBuf,"EHLO %s\r\n",GetLocalHostName()!=NULL ? m_sLocalHostName.c_str() : "domain");
SendData();
bAccepted = false;
do
{
ReceiveData();
switch(SmtpXYZdigits())
{
case 250:
bAccepted = true;
break;
default:
throw ECSmtp(ECSmtp::COMMAND_EHLO);
}
}while(!bAccepted);
if ( bAuthRequired ) {
strcpy(SendBuf,"AUTH LOGIN\r\n");
SendData();
bAccepted = false;
do
{
ReceiveData();
switch(SmtpXYZdigits())
{
case 250:
break;
case 334:
bAccepted = true;
break;
default:
throw ECSmtp(ECSmtp::COMMAND_AUTH_LOGIN);
}
}while(!bAccepted);
if(!m_sLogin.size())
throw ECSmtp(ECSmtp::UNDEF_LOGIN);
std::string encoded_login = base64_encode(reinterpret_cast<const unsigned char*>(m_sLogin.c_str()),m_sLogin.size());
sprintf(SendBuf,"%s\r\n",encoded_login.c_str());
SendData();
bAccepted = false;
do
{
ReceiveData();
switch(SmtpXYZdigits())
{
case 334:
bAccepted = true;
break;
default:
throw ECSmtp(ECSmtp::UNDEF_XYZ_RESPONSE);
}
}while(!bAccepted);
if(!m_sPassword.size())
throw ECSmtp(ECSmtp::UNDEF_PASSWORD);
std::string encoded_password = base64_encode(reinterpret_cast<const unsigned char*>(m_sPassword.c_str()),m_sPassword.size());
sprintf(SendBuf,"%s\r\n",encoded_password.c_str());
SendData();
bAccepted = false;
do
{
ReceiveData();
switch(SmtpXYZdigits())
{
case 235:
bAccepted = true;
break;
case 334:
break;
case 535:
throw ECSmtp(ECSmtp::BAD_LOGIN_PASS);
default:
throw ECSmtp(ECSmtp::UNDEF_XYZ_RESPONSE);
}
}while(!bAccepted);
}
if(!m_sMailFrom.size())
throw ECSmtp(ECSmtp::UNDEF_MAIL_FROM);
sprintf(SendBuf,"MAIL FROM:<%s>\r\n",m_sMailFrom.c_str());
SendData();
bAccepted = false;
do
{
ReceiveData();
switch(SmtpXYZdigits())
{
case 250:
bAccepted = true;
break;
default:
throw ECSmtp(ECSmtp::COMMAND_MAIL_FROM);
}
}while(!bAccepted);
if(!(rcpt_count = Recipients.size()))
throw ECSmtp(ECSmtp::UNDEF_RECIPIENTS);
for(i=0;i<Recipients.size();i++)
{
sprintf(SendBuf,"RCPT TO:<%s>\r\n",(Recipients.at(i).Mail).c_str());
SendData();
bAccepted = false;
do
{
ReceiveData();
switch(SmtpXYZdigits())
{
case 250:
bAccepted = true;
break;
default:
rcpt_count--;
}
}while(!bAccepted);
}
if(rcpt_count <= 0)
throw ECSmtp(ECSmtp::COMMAND_RCPT_TO);
for(i=0;i<CCRecipients.size();i++)
{
sprintf(SendBuf,"RCPT TO:<%s>\r\n",(CCRecipients.at(i).Mail).c_str());
SendData();
bAccepted = false;
do
{
ReceiveData();
switch(SmtpXYZdigits())
{
case 250:
bAccepted = true;
break;
default:
; }
}while(!bAccepted);
}
for(i=0;i<BCCRecipients.size();i++)
{
sprintf(SendBuf,"RCPT TO:<%s>\r\n",(BCCRecipients.at(i).Mail).c_str());
SendData();
bAccepted = false;
do
{
ReceiveData();
switch(SmtpXYZdigits())
{
case 250:
bAccepted = true;
break;
default:
; }
}while(!bAccepted);
}
strcpy(SendBuf,"DATA\r\n");
SendData();
bAccepted = false;
do
{
ReceiveData();
switch(SmtpXYZdigits())
{
case 354:
bAccepted = true;
break;
case 250:
break;
default:
throw ECSmtp(ECSmtp::COMMAND_DATA);
}
}while(!bAccepted);
FormatHeader(SendBuf);
SendData();
if(GetMsgLines())
{
for(i=0;i<GetMsgLines();i++)
{
sprintf(SendBuf,"%s\r\n",GetMsgLineText(i));
SendData();
}
}
else
{
sprintf(SendBuf,"%s\r\n"," ");
SendData();
}
if((FileBuf = new char[55]) == NULL)
throw ECSmtp(ECSmtp::LACK_OF_MEMORY);
if((FileName = new char[255]) == NULL)
throw ECSmtp(ECSmtp::LACK_OF_MEMORY);
TotalSize = 0;
for(FileId=0;FileId<Attachments.size();FileId++)
{
strcpy(FileName,Attachments[FileId].c_str());
sprintf(SendBuf,"--%s\r\n",BOUNDARY_TEXT);
strcat(SendBuf,"Content-Type: application/x-msdownload; name=\"");
strcat(SendBuf,&FileName[Attachments[FileId].find_last_of("\\") + 1]);
strcat(SendBuf,"\"\r\n");
strcat(SendBuf,"Content-Transfer-Encoding: base64\r\n");
strcat(SendBuf,"Content-Disposition: attachment; filename=\"");
strcat(SendBuf,&FileName[Attachments[FileId].find_last_of("\\") + 1]);
strcat(SendBuf,"\"\r\n");
strcat(SendBuf,"\r\n");
SendData();
hFile = fopen(FileName,"rb");
if(hFile == NULL)
throw ECSmtp(ECSmtp::FILE_NOT_EXIST);
FileSize = 0;
while(!feof(hFile))
FileSize += fread(FileBuf,sizeof(char),54,hFile);
TotalSize += FileSize;
if(TotalSize/1024 > MSG_SIZE_IN_MB*1024)
throw ECSmtp(ECSmtp::MSG_TOO_BIG);
else
{
fseek (hFile,0,SEEK_SET);
MsgPart = 0;
for(i=0;i<FileSize/54+1;i++)
{
res = fread(FileBuf,sizeof(char),54,hFile);
MsgPart ? strcat(SendBuf,base64_encode(reinterpret_cast<const unsigned char*>(FileBuf),res).c_str())
: strcpy(SendBuf,base64_encode(reinterpret_cast<const unsigned char*>(FileBuf),res).c_str());
strcat(SendBuf,"\r\n");
MsgPart += res + 2;
if(MsgPart >= BUFFER_SIZE/2)
{ MsgPart = 0;
SendData(); }
}
if(MsgPart)
{
SendData(); }
}
fclose(hFile);
}
delete[] FileBuf;
delete[] FileName;
if(Attachments.size())
{
sprintf(SendBuf,"\r\n--%s--\r\n",BOUNDARY_TEXT);
SendData();
}
strcpy(SendBuf,"\r\n.\r\n");
SendData();
bAccepted = false;
do
{
ReceiveData();
switch(SmtpXYZdigits())
{
case 250:
bAccepted = true;
break;
default:
throw ECSmtp(ECSmtp::MSG_BODY_ERROR);
}
}while(!bAccepted);
strcpy(SendBuf,"QUIT\r\n");
SendData();
bAccepted = false;
do
{
ReceiveData();
switch(SmtpXYZdigits())
{
case 221:
bAccepted = true;
break;
default:
throw ECSmtp(ECSmtp::COMMAND_QUIT);
}
}while(!bAccepted);
#ifdef LINUX
close(hSocket);
#else
closesocket(hSocket);
#endif
hSocket = NULL;
}
bye
|
|
|
|

|
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.
|
|
|
|

|
FWIW, I modified Send so that if m_sLogin.size() was > 0, then it does authentication.
Not every mail server requires authentication....
I also had to replace GetLocalHostName as you did...embedded systems don't really have hostnames....
|
|
|
|

|
Thanks. But I got an error message-
Error: Server returned error after sending EHLO.
Max
|
|
|
|
|
|
|

|
What is buo? Are you using your own language
Jakub Piwowarczyk
|
|
|
|

|
This code is absolutely great! Maybe I'm missing something but how would I send an email with an HTML formatted message body?
Thanks again for the great class!
|
|
|
|

|
If you want to send html use the following content types tags:
STRACTURE THE SAME LIKE BEFORE...
--_004_4D3BE6D5235E6B4386FE7FA971A355B71CACAF9127018DNAMSG0101_ <= set your own id
Content-Type: multipart/alternative;
boundary="_004_4D3BE6D5235E6B4386FE7FA971A355B71CACAF9127018DNAMSG0101_"
--_004_4D3BE6D5235E6B4386FE7FA971A355B71CACAF9127018DNAMSG0101_
Content-Type: text/plain; charset="iso-8859-2" <= here put your charset
Content-Transfer-Encoding: quoted-printable
PLAIN TEXT HERE...
--_004_4D3BE6D5235E6B4386FE7FA971A355B71CACAF9127018DNAMSG0101_
Content-Type: text/html; charset="iso-8859-2"
Content-Transfer-Encoding: quoted-printable
HTML HERE...
--_004_4D3BE6D5235E6B4386FE7FA971A355B71CACAF9127018DNAMSG0101_--
--_004_4D3BE6D5235E6B4386FE7FA971A355B71CACAF9127018DNAMSG0101_
Content-Type: image/jpeg; name="image001.jpg"
Content-Description: image001.jpg
Content-Disposition: inline; filename="image001.jpg"; size=4231;
creation-date="Thu, 29 Jul 2010 04:58:23 GMT";
modification-date="Thu, 29 Jul 2010 04:58:23 GMT"
Content-ID: <image001.jpg@01CB2F26.1C363B50>
Content-Transfer-Encoding: base64
IMAGE IN BASE64 HERE...
For additional informations read proper RFC documents.
Jakub Piwowarczyk
|
|
|
|

|
Using the CSmtp to send emails and it is working fine (one little problem is that when I send to a hotmail.com it always goes into the junk folder).
I need to send a HTML email and I just do not understand ANYTHING about the example you give above.
Could / would you please provide an actual example
Thanks
Bob Valentino
|
|
|
|

|
Error:Server returned error after sending EHLO
I use version 1.5 code, can send mail normally, but when I use version 1.8, it show the error.
I sure login information is right.
|
|
|
|

|
I got the same problem with you,
Could someone tell us why?
|
|
|
|

|
Could one of You make two tests for me:
1. in Smtp client class 1.5 ver copy buffer state after ReceiveData() was called
2. do the same for ver 1.8
and send me your results (on forum), it will be helpful for me to determine the reason for this bug
Jakub Piwowarczyk
|
|
|
|

|
I am using v1.8 on linux, i have the same problem. Is this bug fixed? How can i help?
|
|
|
|
|

|
Hi All,
Here there is small syntax issue in SMTP send mail function.
change the ELHO to HELO.
HELO is the correct protocol.
Its working for me.
Regards,
Ayyavu P
Ayyavu P
Updating mind
|
|
|
|

|
it's not problem here ...
read bug fixes.
..should correct issue
|
|
|
|

|
Prolly I post this a bit later, but started using your program and encountered the very same issue.
I managed to resolve it(for me atleast) tho, the problem is caused by those lines:
const char* CSmtp::GetLocalHostName() const
{
char* str = NULL;
if((str = new char[255]) == NULL)
throw ECSmtp(ECSmtp::LACK_OF_MEMORY);
if(gethostname(str,255) == SOCKET_ERROR)
{
delete[] str;
throw ECSmtp(ECSmtp::WSA_HOSTNAME);
}
delete[] str;
return m_sLocalHostName.c_str();
}
I am using win7 and VS2008(yes, converted it to it), for me atleast m_sLocalHostName is not setting anywhere, causing the
sprintf(SendBuf,"EHLO %s\r\n",GetLocalHostName()!=NULL ? m_sLocalHostName.c_str() :"domain");
SendData();
line to fail
(since it's not NULL but still is empty string, whethere there should be the host name it gives an empty string).
That's about it.
There should be one "else" for the if(gethostname(str,255) == SOCKET_ERROR) that returns the proper local host name, or you can fill the m_sLocalHostName itself(but for that you should change the prototype of the function to not be "const" )
Hope I helped
|
|
|
|

|
Hi,
Thank you for the code.
I found issue with AddMsgLine method. I convert the code into static library and include into my application.
The application crashed when i call the method trying to add the line to message body (compiled on Windows XP and VC++8) in release configuration (in debug all is working fine)
I don't know why but access violation exception in the method. Actually it happens in STL vector assign.
void AddMsgLine(const char* Text)
{
MsgBody.insert(MsgBody.end(), Text);
}
I have replaced this for
void AddMsgLine(const char* Text)
{
MsgBody.push_back(Text);
}
and all became fine without exception.
|
|
|
|

|
very nice code, thank you.
|
|
|
|

|
I want to rename the attachment.
Can you please tell me how it can be done?
Thanks.
|
|
|
|

|
I would say it's more natural not to have the logic of renaming the attachments being a part of a SMTP lib.
Max
|
|
|
|

|
This is just working like a charm..
but when i execute the application Kaspersky Internet Security pops up and warning me Its highly dangers coz the application is not digitally signed.
i just played with the code & i found that.
if i comment the mail.Send() line in main.cpp.. antivirus not warning me..
if i remove the comment then it warns..
any idea to solve this problem
thank u very much this is an awesome job.
|
|
|
|

|
There is nothing suprising that uncommenting Send() will turn off warnings - this function does the main job in the programe as well as connecting to the reomote server. If you are using firewall or antivirus with firewall it will block even commercial programs like iexplorer. So you ought to add this program to "trusted programs" and that is it.
Jakub Piwowarczyk
|
|
|
|

|
Its working like a charm.
|
|
|
|

|
I just started using this code and found that my email server was rejecting the email that was being sent due to the EHLO command on line 351 was not sending the hostname of the system that it was running on, due to m_sLocalHostName never being initialized.
What I wound up doing was:
1) remove the trailing const in the definition of the GetLocalHostName() function on line 1149 of CSmtp.cpp
2) right before the delete of str added the following line:
m_sLocalHostName.assign(( char * ) str);
3) removed the trailing const on line 129 where GetLocalHostName() is declared in CSmtp.h
Without removing consts in steps 1 and 3 I was getting a compiler error for step 2.
Hope this helps.
|
|
|
|

|
Hi,
To fix it you could do:
1. Change function GetLocalHostName
const char* CSmtp::GetLocalHostName() const
{
return m_sLocalHostName.c_str();
}
2. Change CSmtp constructor
CSmtp::CSmtp()
{
m_iXPriority = XPRIORITY_NORMAL;
m_iSMTPSrvPort = 0;
#ifndef LINUX
WSADATA wsaData;
WORD wVer = MAKEWORD(2,2);
if (WSAStartup(wVer,&wsaData) != NO_ERROR)
throw ECSmtp(ECSmtp::WSA_STARTUP);
if (LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 )
{
WSACleanup();
throw ECSmtp(ECSmtp::WSA_VER);
}
#endif
char* str = NULL;
if((str = new char[255]) == NULL)
throw ECSmtp(ECSmtp::LACK_OF_MEMORY);
if(gethostname(str,255) == SOCKET_ERROR)
{
delete[] str;
throw ECSmtp(ECSmtp::WSA_HOSTNAME);
}
m_sLocalHostName.insert(0,str);
delete[] str;
if((RecvBuf = new char[BUFFER_SIZE]) == NULL)
throw ECSmtp(ECSmtp::LACK_OF_MEMORY);
if((SendBuf = new char[BUFFER_SIZE]) == NULL)
throw ECSmtp(ECSmtp::LACK_OF_MEMORY);
}
3. Change one line in Send fiunction
sprintf(SendBuf,"EHLO %s\r\n",GetLocalHostName());
SendData();
bAccepted = false;
Let me know if it didn't help.
Jakub Piwowarczyk
|
|
|
|

|
Yes, This seems like fixed the bug.
|
|
|
|

|
nice solution !! it works !
|
|
|
|

|
write this
mail.SetSMTPServer("smtp.gmail.com",25);
mail.SetLogin("moi_login@gmail.com");
mail.SetPassword("parol");
mail.SetSenderName("moi_login");
mail.SetSenderMail("moi_login@gmail.com");
mail.SetReplyTo("moi_login@gmail.com");
mail.SetSubject("The message");
mail.AddRecipient("moi_login@gmail.com");
mail.SetXPriority(XPRIORITY_NORMAL);
mail.SetXMailer("The Bat! (v3.02) Professional");
mail.AddMsgLine("Hello,");
mail.AddMsgLine("");
mail.AddMsgLine("...");
mail.AddMsgLine("How are you today?");
mail.AddMsgLine("hgh");
mail.AddMsgLine("Regards");
mail.ModMsgLine(5,"regards");
mail.DelMsgLine(2);
mail.AddMsgLine("User");
but always I have error
Error: Server returned error after sending AUTH LOGIN
Why this happend?
|
|
|
|
|
|

|
My body mail is upper 10000 caractere and each time, i have an error.
How I can send a message with more 10000 caracteres
Thank you for our help
Hubert Jost
|
|
|
|

|
Hi,
But you don't have one line with 10000 c?
Each line is vector's element:
std::vector<std::string> MsgBody;
Jakub Piwowarczyk
|
|
|
|

|
Great Code Man!
This is the first opensource working C++ SMTP class i've come accross.
Just wanted to share a small bug I found:
Some SMTP servers usually greet the client with more than one line on connection.
example,
220-gt2.websitewelcome.com ESMTP Exim 4.69 #1 Fri, 30 Jul 2010 05:41:08 -0500
220-We do not authorize the use of this system to transport unsolicited,
220 and/or bulk e-mail.
Since this class reads responses one line at a time, it will read the first line
220-gt2.websitewelcome.com ESMTP Exim 4.69 #1 Fri, 30 Jul 2010 05:41:08 -0500
Send EHLO Then read the second line
220-We do not authorize the use of this system to transport unsolicited,
parse the line and since it isn't the expected response -> 250 the ECSmtp
exception will be thrown. While all along the server gave a correct reply.
I got around this by reading thrice at the begining (I needed a quick fix)
......
bAccepted = false;
do
{
ReceiveData();
ReceiveData();
ReceiveData();
switch(SmtpXYZdigits())
{
case 220:
bAccepted = true;
break;
default:
throw ECSmtp(ECSmtp::SERVER_NOT_READY);
......
Otherwise your code is a godsend.
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
The CSmtp class allows to send emails with attachments. It only provides the AUTH LOGIN authentication.
| Type | Article |
| Licence | CPOL |
| First Posted | 24 Aug 2008 |
| Views | 177,958 |
| Downloads | 7,356 |
| Bookmarked | 159 times |
|
|