Roman S
Roman S

Reputation: 33

SMTP client with SSL connection

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

Answers (2)

mti2935
mti2935

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

Remy Lebeau
Remy Lebeau

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

Related Questions