|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
Introduction
The CSmtp class allows to send emails from your program. The inspiration to write the CSmtp class was the article [1]. I have used the code of CFastSmtp and introduced the following changes:
- some bags have been removed (i.e. free memory),
- logining with authentication have been applied (AUTH LOGIN),
- sending attachments have been added,
- errors handling have been modified,
- new headlines from MIME specifications (i.e. X-Priority) have been added.
Typical scenarios while sending the email
After successfull connection to the SMTP server, our client starts the conversation between the remote SMTP server. Each line send by the client ought to be finished by "\r\n". If you want to know more details, check [2], [3], [4], [5], [6], [7], [8] and [9]. In [2] was described original SMTP protocol (1982),in [4] were discussed SMTP extensions for authentication and MIME specification was improved in [5]-[9]. Example 3 failed becouse 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, xxx - means information censured.
Example 1 - Connecting to smtp.wp.pl and using incorrect login or password
S: 220 smtp.wp.pl ESMTP
C: EHLO: mydomain.com
S: 250-smtp.wp.pl
250-PIPELINING
250-AUTH=LOGIN PLAIN
250-AUTH LOGIN PLAIN
250-STARTTLS
250-SIZE
250-X-RCPTLIMIT 100
250-8BITMIME
C: AUTH LOGIN
S: 334 VXNlcm5hbWU6
C: Kioq
S: 334 UGFzc3dvcmQ6
C: Kioq
S: 535 blad autoryzacji, niepoprawny login lub haslo / auth failure
Example 2 - Connecting to smtp.wp.pl and using correct login and password
S: 220 smtp.wp.pl ESMTP
C: EHLO: mydomain.com
S: 250-smtp.wp.pl
250-PIPELINING
250-AUTH=LOGIN PLAIN
250-AUTH LOGIN PLAIN
250-STARTTLS
250-SIZE
250-X-RCPTLIMIT 100
250-8BITMIME
C: AUTH LOGIN
S: 334 VXNlcm5hbWU6
C: xxx
S: 334 UGFzc3dvcmQ6
C: xxx
S: 235 go ahead
C: MAIL FROM:<me@mydomain.com>
S: 250 ok
C: RCPR TO:<friend@domain.com>
S: 250 ok
C: DATA
S: 234 go ahead
C: Date: Sun, 24 Aug 2008 22:43:45
From: JP<mail@domain.com>
X-Mailer: The Bat! (v3.02) Professional
Replay-to:mail@domain.com
X-Priority: 3 (Normal)
To:<friend@domain.com>
Subject: The message
MIME Version 1.0
Content-Type: multipart/mixed; boundary="__MESSAGE__ID__54yg6f6h6y456345"
--__MESSAGE__ID__54yg6f6h6y456345
Content-type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
This is my message.
--__MESSAGE__ID__54yg6f6h6y456345
Content-Type: application/x-msdownload; name="test.exe"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="test.exe"
TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
(...)
SU5HWFhQQURESU5HUEFERElOR1hYUEFERElOR1BBRERJTkdYWFBBRERJTkdQQURESU5HWA==
--__MESSAGE__ID__54yg6f6h6y456345
Content-Type: application/x-msdownload; name="test2.jpg"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="test2.jpg"
/9j/4Sv+RXhpZgAASUkqAAgAAAAJAA8BAgAGAAAAegAAABABAgAWAAAAgAAAABIBAwABAAAA
(...)
A6YxR5YJJ5zUu6ZW4+NjC24E4q5Dcox5I+lRI0iWAAV9aay+lTctoYTjrml+9irRmz//2Q==
--__MESSAGE__ID__54yg6f6h6y456345--
.
S: 250 ok xxx qp xxx
C: QUIT
S: 221 smtp.wp.pl
Example 3 - Connecting to smtp.gmail.com
S: 220 mx.google.com ESMTP
w28sm1561195uge.4
C: EHLO: mydomain.com
S: 250-mx.google.com at your service [xxx.xxx.xxx.xxx],
250-SIZE 28311552
250-8BITMIME
250-STARTTLS
250 ENHANCEDSTATUSCODES
C: AUTH LOGIN
S: 530 5.7.0 Must issue a STARTTLS command first. w28sm1561195uge.4
Example 4 - Connecting to smtp.bizmail.yahoo.com and using incorrect login or password
S: 220 smtp103.biz.mail.re2.yahoo.com ESMTP
C: EHLO: mydomain.com
S: 250-smtp103.biz.mail.re2.yahoo.com
250-AUTH LOGIN PLAIN XYMCOOKIE
250-PIPELINING
250-8BITMIME
C: AUTH LOGIN
S: 334 VXNlcm5hbWU6
C: dG9t
S: 334 UGFzc3dvcmQ6
C: bmVyb24xMg==
S: 535 authorization failed (#5.7.0)
Implementation of the CSmtp class
- Initialise winsock2 (function: WSAStartup)
- Connect to the remote server (functions: gethostbyname, gethostbyaddr, socket, htons, getservbyname)
- Introduce yourself - EHLO <SP> <domain> <CRLF>
- Send AUTH LOGIN <CRLF> and another commands described in "Typical scenarios while sending the email" (functions: send, recv)
- Finish conversation with QUIT <CRLF>
- Free winsock2 resources (function: WSACleanup)
Usage
#include "CSmtp.h"
#include <conio.h>
int main()
{
CSmtp mail;
if(mail.GetLastError() != CSMTP_NO_ERROR)
{
printf("Unable to initialise winsock2.\n");
return -1;
}
mail.SetLogin("***");
mail.SetPassword("***");
mail.SetSenderName("JP");
mail.SetSenderMail("mail@domain.com");
mail.SetReplyTo("mail@domain.com");
mail.SetSubject("The message");
mail.AddRecipient("friend@domain.com");
mail.SetXPriority(XPRIORITY_NORMAL);
mail.SetXMailer("The Bat! (v3.02) Professional");
mail.SetMessageBody("This is my message.");
mail.AddAttachment("c:\\test.exe");
mail.AddAttachment("c:\\test2.jpg");
if( !mail.ConnectServer("smtp.wp.pl",25) )
{
printf("Unable to connect to the server.\n");
return -1;
}
if( mail.Send() )
printf("The mail was send successfully.\n");
else
printf("Unable to send the mail.\n");
mail.Disconnect();
return 0;
}
Author's notices
- If you will have problems to send the email use the Visual Studio's debuger and analyse the conversation between your SMTP server, perhaps your server needs differend kind of the authentication or doesn't need it at all.
- You are not allowed to use CSmtp class to produce the spam.
Bibliography
- CFastSmtp - Fast and easy SMTP class...
- SIMPLE MAIL TRANSFER PROTOCOL RFC 821
- STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT MESSAGES RFC 822
- SMTP Service Extension for Authentication RFC 2554
- MIME: Format of Internet Message Bodies RFC 2045
- MIME: Media Types RFC 2046
- MIME: Message Header Extensions for Non-ASCII Text RFC 2047
- MIME: Registration Procedures RFC 2048
- MIME: Conformance Criteria and Examples RFC 2049
| You must Sign In to use this message board. |
|
| | Msgs 1 to 16 of 16 (Total in Forum: 16) (Refresh) | FirstPrevNext |
|
 |
|
|
Hello,
First of all, thanks a lot for the code. One can find on the web a lot of code snippets for sending emails but none are really taking care of what the server responds.
I've modified the code to use it under Linux in C and came across the following remarks:
1) There's a typo on the HELO command that is spelled EHLO in the code. Even though it does not seem to be a problem for some SMTP servers, it is for some others.
2) I would add a test on the creation of amongst others FileBuf, FileName, m_pcRemoteHostName, to, cc, bcc ... to see if the allocation succeeded.
3) At line 671, a check is made on m_pcNameFrom to see if it's not NULL and if it is, the pointer is used as a destination in a strcpy. The same check is done in the line below with then more correct behaviour; I suppose the first should be simply removed.
4) At line 740, the code to be executed when m_pcSubject is NULL does not look complete. The plain code is executed anyway after the test; I assume the else is missing here.
Best regards, J-C
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Hi,
You're right, I overlooked that point.
Looking back into this and strange enough, the server that made me problems tells in its greeting that it supports ESMTP but rejects the EHLO command with a 502 error... Very bizarre but not related to the code here anyway.
Best regards, J-C
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I sent an email using the original code, and my ISP add these lines to the email as a Spam Report...
X-Spam-Report: Spam detection software, running on the system "guinea.dattaweb.com", has identified this incoming email as possible spam. The original message has been attached to this so you can view it (if it isn't spam) or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Este es el cuerpo del mail [...] Content analysis details: (0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.4 ALL_TRUSTED Passed through trusted hosts only via SMTP 0.0 MISSING_MID Missing Message-Id: header 1.7 INVALID_DATE Invalid Date: header (not RFC 2822)
The important thing is at the end of the report, where it reports an invalid Date format. This is solved if we add +0000 in the FormatHeader funcion as is shown below ... SYSTEMTIME st={0}; ::GetSystemTime(&st); ::GetDateFormat(MAKELCID(0x0409,SORT_DEFAULT),0,&st,"ddd\',\' dd MMM yyyy",szDate,sizeof(szDate)); ::GetTimeFormat(MAKELCID(0x0409,SORT_DEFAULT),TIME_FORCE24HOURFORMAT,&st,"HH\':\'mm\':\'ss",sztTime,sizeof(sztTime)); sprintf(header,"Date: %s %s +0000\r\n", szDate, sztTime);
...
Bye
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi, Thank you for your suggestion. +0000 will depend on zone. I have noticed that "The Bat" put "+002" to my messages, but I have ignored it so far.
JP
Jakub Piwowarczyk
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Your code dont seemed to work too well with MFC. Your code works fine under the console environment but under MFC, it always return the Invalid winsock2 socket error. Any idea why this is so? I used VS08 btw. So I dont think I would have any problem with ws2.
Thanks, Mike.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I don't like MFC, but for you I had made an exception. Below step was made for MFC in VC6. what to do: 1. Create MFC app i.e.: mail.exe (I didn't mark Windows socket in wizard). 2. Add CSmtp.cpp, CSmtp.h, base64.cpp, base64.h to the project directory and add files to project. 3. Set for CSmtp.cpp and base64.cpp "not using precompiled headers". 4. Add "CSmtp mail;" variable to CMailDlg class 5. Set default values in mail variable (in BOOL CMailDlg::OnInitDialog()) 6. Add action void CMailDlg::OnOK(), i.e.: void CMailDlg::OnOK() { UpdateData(TRUE);
mail.SetLogin(m_strLogin); mail.SetPassword(m_strPassword); mail.AddRecipient(m_strMail); mail.SetMessageBody(m_strMessage);
if( !mail.ConnectServer("smtp.server.com",25) ) { MessageBox("Unable to connect to the server."); } else { if( mail.Send() ) MessageBox("The mail was send successfully."); else MessageBox("Unable to send the mail."); } mail.Disconnect();
CDialog::OnOK(); }
7. Send the mail.
Jakub Piwowarczyk
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Yes I did exactly like you said. But still got the same error message "Invalid winsock2 socket". I am still not sure why I am keep getting this error. . When I tested your code under the console environment with another built, I dont have any problem with it, works fine, however under the MFC/Windows environment, it seemed something is missing. . Thanks anyway for your response.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi, great class. But there is a problem when there is no attachment. In this case, the body of the sent message has
--__MESSAGE__ID__54yg6f6h6y456345--
at the end. I have found that modifying the code of Send() like this seems to fix it.
// sending last message block
if(Attachments.size()) // Only end section if we added attachments { sprintf(SendBuf,"\r\n--%s--\r\n",BOUNDARY_TEXT); if(!SendData()) return false; }
Is this the correct fix, or will there be unexpected consequences?
Regards, Geoff.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
You have absolutely right. I have fixed it and replaced the source code. Thanks for reporting it.
Jakub Piwowarczyk
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
This is really nice job,
However I have q query if it is possible to use it from managed .NET environment. i.e C# or VB.
dnpro "Very bad programmer"
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
well, I am not expert in .NET, becose I haven't written bigger programs in that language so far, but you should introduce the following changes: 1. main function is declared in class: using System; class CMainClass { static void Main() { Console.WriteLine("Hwllo!"); } } 2. in main function use System.Console.Write instead printf 3. in. NET you have garbage collection, so you don't have to use delete 4. rewrite CSmtp class as you do that in .NET 5. according to reinterpret_cast read this: http://www.codeproject.com/KB/mcpp/castingbasics.aspx
Jakub Piwowarczyk
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
 |
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|