Reputation: 33
I have next sample code of using SMTP client, when I am trying to send mail via mail which uses SSL I get the following:
550 SMTP is available only with SSL or TLS connection enabled.
How I can extend this sample to implement SSL,, for example to send e-mail via gmail, etc... I prefer socket coding and no external library:
int main()
{
if (FAILED (WSAStartup (MAKEWORD( 1,1 ), &ws)))
{
printf("Error in WSAStartup(...)\n");
return 1; }
// creating socket
s = socket (AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET)
{
printf("Error in socket(...)\n");
return 1; }
//get server address
d_addr = gethostbyname ("smtp.mail.ru");
if (d_addr==NULL)
{
printf("Error in gethostbyname(...)\n");
return 1; };
// fill address parameters
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = *((unsigned long *) d_addr->h_addr);
addr.sin_port = htons (25);
// connecting...
if (SOCKET_ERROR == (connect (s, (sockaddr *) &addr,
sizeof (addr))))
{
printf("Error in connect(...)\n");
return 1; }
// waiting from answer from server
recv(s,text,sizeof(text),0);
printf("recv - %s", text);
// sy hello to server
strcpy(text,"HELO smtp.mail.ru\r\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
// waiting approve from server
recv(s,text,sizeof(text),0);
printf("recv - %s", text);
// set sender
strcpy(text,"MAIL FROM: [email protected]\r\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
// waiting for approve
recv(s,text,sizeof(text),0);
printf("recv - %s", text);
// set receiver
strcpy(text,"RCPT TO: [email protected]\r\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
// waiting for approve
recv(s,text,sizeof(text),0);
printf("recv - %s", text);
// ready to start sending letter
strcpy(text,"DATA\r\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
// waiting for approve
recv(s,text,sizeof(text),0);
printf("recv - %s", text);
// from whom letter
strcpy(text,"FROM: [email protected]\r\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
// receiver
strcpy(text,"TO: [email protected]\r\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
// letter subject
strcpy(text,"SUBJECT: test\r\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
// letter text
strcpy(text,"Hi!\nIt is a message for you\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
// telling that we finish
strcpy(text,"\r\n.\r\n");
send(s,text,strlen(text),0);
printf("send - %s", text);
recv(s,text,sizeof(text),0);
printf("recv - %s", text);
// quit
strcpy(text,"QUIT");
send(s,text,strlen(text),0);
printf("send - %s", text);
// close socket
closesocket(s);
return 0;
}
Upvotes: 1
Views: 3237
Reputation: 12027
Another way to solve this problem may be to run your C program under Scott Gifford's sslclient (see http://www.superscript.com/ucspi-ssl/sslclient.html). sslclient will spawn your program and open an SSL connection to the server on the port that you specify, and pipe your program's stdout to the server, and pipe output from the server to your program's stdin. The nice thing about doing it this way is that you can let sslclient to all the heavy lifting as far as setting up the sockets and ssl, etc., and you can focus on the core function of your program.
Upvotes: 0
Reputation: 597036
The server is telling you that you sent an SMTP command that requires the socket connection to be in a secure state first (though the server should be using reply code 530
for that purpose instead).
You are connecting to port 25, which is traditionally an unencrypted SMTP port. The encrypted SMTP ports are typically 465 (implicit SSL) and 587 (explicit TLS) instead.
You are also using the HELO
command, which is outdated. You should be using the EHLO
command instead (see RFC 2821 Section 4.1.1.1). That will allow the server to send you a list of its capabilities (in particular its current security and authentication settings).
On ports 25 and 587, SMTP communications are initially unencrypted. You can connect and immediately receive the server's SMTP greeting and send your initial HELO
/EHLO
command. If the EHLO
reply includes the STARTTLS
capability (see RFC 3207), you can send a STARTTLS
command to initiate a SSL/TLS handshake to encrypt communications from that moment onward. After STARTTLS
is successful, send a new EHLO
command to get updated capabilities before sending any subsequent commands.
On port 465, SMTP communications are always encrypted. You must start a SSL/TLS handshake immediately upon connecting to the server, before it can send its SMTP greeting and you send your initial HELO
/EHLO
command.
Now, regarding the SSL/TLS session itself, there are plenty of different ways you can implement that, but DO NOT try to implement SSL/TLS from scratch! It is very complicated and you are going to get it wrong. Use an existing external API/library that does all of the hard work for you. To add SSL/TLS on top of your existing socket code, you can use OpenSSL, or Microsoft's Crypto API (in particular, its SChannel provider), or even WinSock's own Secure Socket extensions. Or, you could replace your manual socket code with a 3rd party library that handles all of the SMTP and SSL/TLS logic for you, such as libcurl.
Upvotes: 4