Command Line SMTP can be programmed using sockets very easily. SMTP or Simple Mail Transfer Protocol has a set of commands to be sent and received. If a program can send the command with the protocol and data to the SMTP server, then it can easily send e-mails. In fact even a telnet session at SMTP port 25 can be used to send e-mails, if the protocol is known properly. This Command Line SMTP in Win32 article explains how to use Win 32 to write an SMTP program.
The following is the set of commands from the SMTP RFC to be sent to the SMTP server to make it listen and accept our e-mails to be sent to the recipients.
Connect to SMTP server using port 25
Expect 220
Send HELO myFQDN
Expect 250
Send MAIL FROM:<From-mail@myFQDN.com>
Expect 250
Send RCPT TO:<mail_address>
Expect 250
Send DATA
Expect 354
Send body of message
Send <CRLF>.<CRLF>
Expect 250
Send QUIT
Expect 221
Close connection
The above is the way an SMTP client and a SMTP server interact between them. All the above strings sent to the Command Line SMTP program, including the e-mail addresses should be appended with \r\n. Otherwise it will not be considered as the end of the line.
Also the received data will contain numbers like 250, 354 etc., in the front. These numbers mean either the messages is accepted or rejected or unrecognized. 500 is the error returned if the command is unrecognized.
Command Line SMTP sample using Win32:
The following sample program can be used to send an e-mail to the SMTP server.
#include <winsock2.h>
#include <windows.h>
#include <iostream.h>
#define MAX_LENGTH 1024
void main()
{
int s_len, r_len;
int skt_Smtp;
int success;
struct sockaddr_in st_Sockaddr;
char recv_Buf[MAX_LENGTH];
char send_Buf[MAX_LENGTH];
//Initialize Sockets
WSADATA wsa;
WSAStartup(MAKEWORD(2, 0), &wsa);
skt_Smtp = socket(AF_INET,SOCK_STREAM,0);
if (skt_Smtp < 0)
{
cout<< "Error Creating Socket"<<endl;
return;
}
else
{
st_Sockaddr.sin_family = AF_INET;
st_Sockaddr.sin_port = htons(25);
//Get the IP address and initialize the structure
st_Sockaddr.sin_addr.s_addr = inet_addr("IPAddress");
success = connect(skt_Smtp,(struct sockaddr *) &st_Sockaddr,sizeof(st_Sockaddr));
r_len = recv(skt_Smtp,recv_Buf,MAX_LENGTH,0);
recv_Buf[r_len] = '\0';
cout<< recv_Buf<<endl;
//Say Hello to the domain
strcpy(send_Buf,"HELO sampledomain.com\r\n");
s_len = send(skt_Smtp,send_Buf,strlen(send_Buf),0);
r_len = recv(skt_Smtp,recv_Buf,MAX_LENGTH,0);
recv_Buf[r_len] = '\0';
cout<< recv_Buf<<endl;
//Send from address
strcpy(send_Buf , "MAIL FROM: frome-mailid@sampledomain.com\r\n");
s_len = send(skt_Smtp,send_Buf,strlen(send_Buf),0);
r_len = recv(skt_Smtp,recv_Buf,MAX_LENGTH,0);
recv_Buf[r_len] = '\0';
cout<< recv_Buf<<endl;
//Send RCPT address
strcpy(send_Buf,"RCPT TO:<toemail-id@sampledomain.com>\r\n");
s_len = send(skt_Smtp,send_Buf,strlen(send_Buf),0);
r_len = recv(skt_Smtp,recv_Buf,MAX_LENGTH,0);
recv_Buf[r_len] = '\0';
cout<< recv_Buf<<endl;
// Send DATA
strcpy(send_Buf,"DATA\r\n");
s_len = send(skt_Smtp,send_Buf,strlen(send_Buf),0);
r_len = recv(skt_Smtp,recv_Buf,MAX_LENGTH,0);
recv_Buf[r_len] = '\0';
cout<< recv_Buf<<endl;
// Send DATA
strcpy(send_Buf,"Subject:Test Win32 command line SMTP Subject\r\n\r\n");
s_len = send(skt_Smtp,send_Buf,strlen(send_Buf),0);
//Send body
strcpy(send_Buf,"Test e-mail for Win32 command line SMTP\r\n.\r\n");
s_len = send(skt_Smtp,send_Buf,strlen(send_Buf),0);
r_len = recv(skt_Smtp,recv_Buf,MAX_LENGTH,0);
recv_Buf[r_len] = '\0';
cout<< recv_Buf<<endl;
//Send QUIT
strcpy(send_Buf,"QUIT\n");
s_len = send(skt_Smtp,send_Buf,strlen(send_Buf),0);
r_len = recv(skt_Smtp,recv_Buf,MAX_LENGTH,0);
recv_Buf[r_len] = '\0';
cout<< recv_Buf<<endl;
closesocket(skt_Smtp);
}
WSACleanup();
}
This program can be compiled as a console application. The items highlighted in BOLD and BLUE colors should be replaced with the right names.
Note: As this program uses sockets, this needs to be linked with ws2_32.lib library. Refer for more information on socket client.