How to use openssl to send email via SMTP server that supports starttls?

If you’ve read my article on how to use openssl to send emails, you may encounter some problem when applying that method to certain kind of SMTP servers such as outlook SMTP server.

openssl s_client  -connect smtp.live.com:587
WARNING: can’t open config file: /usr/local/ssl/openssl.cnf
Loading ‘screen’ into random state – done
CONNECTED(00000774)
5100:error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol:.\ssl\s
23_clnt.c:787:

no peer certificate available

No client certificate CA names sent

SSL handshake has read 7 bytes and written 307 bytes

New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE

smtp.live.com is the outlook.com smtp. It uses the port 587 instead of 465  as usual SMTP servers to receive emails. You can get to know the difference between port 587 and 465 in this post. Basically, SMTP server using port 465 will create an SSL session immediately after the TCP connection is established(the SYN, SYN+ACK, ACK sequence). All the communication thereafter will be done in  secure way.  SMTP server using port 587 will communication with client in plain(unencrypted) text until a STARTTLS command is issued. After the STARTTLS command is issued, the communication between client and SMTP server is encrypted using SSL mechanism.

To understand why openssl fails to connect to outlook server, we need to know how openssl s_client works. openssl can do many things, too many to understand them all. s_client is a sub-command of openssl, which is used to connect remote server. In the simple form of the command like above, openssl initiates the ssl(tls) handshake process by sending a “Client Hello” packet to the server right after the tcp connection is established. But SMTP server listening on port 587 is not ready for an ssl handshake for now. Maybe it responses with a “ESMTP server ready…” message. The openssl client cannot get the expected “server hello” SSL packet so it prints the error “SSL23_GET_SERVER_HELLO:unknown” and resets the tcp connection.

If smtp server is listening on port 465, it will reply to the “client hello” with a “server hello”. The “server hello” also includes the server’s digital certificate which is printed by the openssl client.   The ssl handshake can be completed successfully.

To send email to the smtp server like outlook.com, the client should not initiate the ssl handshake too early, but wait till the STARTTLS command is sent. Theoretically,  we can use telnet to connect to smtp.live.com:587 and issue the STARTTLS command manually. But we can also use another form of the openssl command:

openssl s_client -starttls smtp -connect smtp.live.com:587

Now, after connecting to the smtp server, openssl does not initiate the ssl handshake immediately, but send a SMTP command EHLO automatically:

EHLO openssl.client.net

outlook smtp server will response with a list of available commands including STARTTLS. Knowing the smtp server supports STARTTLS, openssl will send the second SMTP command STARTTLS automatically. The SMTP server responds with “220 2.0.0 SMTP server ready\r\n” meaning the server is ready for creating a ssl session. Now openssl starts the ssl handshake by sending the “client hello” as in usual ssl handshaking process. After the handshaking is completed, openssl prints the certification and ssl session information and wait for you to input further command.

Now you can issue the normal SMTP commands to send email as we talked about in my previous post. If you send the “mail from” command directly, you will get the following error:

503 5.5.2 Send hello first [xxxxxxx.namprd16.prod.outlook.com]

We should issue the EHLO command first although openssl has sent this command once automatically.

ehlo localhost
250-xxxxxx.outlook.office365.com Hello [xx.xx.xx.xx]
250-SIZE 154566400
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-AUTH LOGIN XOAUTH2
250-8BITMIME
250-BINARYMIME
250-CHUNKING
250 SMTPUTF8

Notice the STARTTLS is missing here because we can issue ony one STARTTLS per session. Now if you issue the “mail from” command, the connection will be terminated with the following error:

530 5.7.57 SMTP; Client was not authenticated to send anonymous mail during MAIL
FROM [xxxxxxxx.namprd16.prod.outlook.com]
read:errno=0

 

Outlook does not allow you to send email regardless the email is destined to outlook.com or other domains. According to the response of EHLO, we know that outlook supports two authentication methods:LOGIN and XOAUTH2. We will use the LOGIN auth method.

Unfortunately, after I input the base64 encoded username and password, openssl exits with the error:

5712:error:1409E0E5:SSL routines:SSL3_WRITE_BYTES:ssl handshake failure:.\ssl\s3
_pkt.c:598:

The error is caused by the capital  first letter of the base64 encoded password string. It turns out what you input should begin with a low-case letter. What a ridiculous bug! The cure would be adding the option -quiet to the “openssl s_client” command line. Note also that if you use the openssl command in Linux, you should use the -crlf option, otherwise after you input a SMTP command and press the enter key, you’ll get no response from the server. So the complete command line of openssl is:

openssl s_client -starttls smtp -connect smtp.live.com:587 -quiet -crlf

Once auth login is completed, the “mail from”,”rcpt to”,”data” commands can be issued without problem, and finally, you can use outlook.com smtp server to send an email.

 

References:

https://www.saotn.org/test-smtp-authentication-starttls/

https://qmail.jms1.net/test-auth.shtml

https://community.letsencrypt.org/t/tutorial-testing-mail-protocols-with-ssl-tls/43211/4

 

Posted in tips of hosting