Implementing Transport Layer Security in Python -

2020-02-12 21:57发布

I have an assignment to write a simple mail client, and to connect to a google smtp server using sockets (without using smtp lib). However, issuing a MAIL FROM command to a google smtp server requires ssl or tls, and this is the part I can't figure out. I'm trying to use Python's ssl.wrap_socket() method thusly....

# Create socket called clientSocket and establish a TCP connection with mailserver
clientSocket = socket(AF_INET, SOCK_STREAM)
ssl_clientSocket = ssl.wrap_socket(clientSocket) 
ssl_clientSocket.connect((mailserver, port))

...which isn't working. I'm pretty sure I need to include the ca_certs and ca_reqs parameters, but I'm not sure. And if this is so, how do I go about obtaining these certificates? Do I have to download openssl and generate one? Anyone with experience with this? Here's the entire code just to be on the safe side.

from socket import *
import ssl

msg = "\r\n I love computer networks!"
endmsg = "\r\n.\r\n"

# Choose a mail server (e.g. Google mail server) and call it mailserver
mailserver = "smtp.gmail.com"
port = 587

# Create socket called clientSocket and establish a TCP connection with mailserver
clientSocket = socket(AF_INET, SOCK_STREAM)
ssl_clientSocket = ssl.wrap_socket(clientSocket) 
ssl_clientSocket.connect((mailserver, port))

recv = ssl_clientSocket.recv(1024)
print
print recv

# If the first three numbers of what we receive from the SMTP server are not
# '220', we have a problem
if recv[:3] != '220':
    print '220 reply not received from server.'

# Send HELO command and print server response.
heloCommand = 'HELO Alice\r\n'
ssl_clientSocket.send(heloCommand)
recv1 = ssl_clientSocket.recv(1024)
print recv1

# If the first three numbers of the response from the server are not
# '250', we have a problem
if recv1[:3] != '250':
    print '250 reply not received from server.'

# Send MAIL FROM command and print server response.
mailFromCommand = 'MAIL From: wgimson@gmail.com\r\n'
ssl_clientSocket.send(mailFromCommand)
recv2 = ssl_clientSocket.recv(1024)
print recv2

# If the first three numbers of the response from the server are not
# '250', we have a problem
if recv2[:3] != '250':
    print '250 reply not received from server.'

# Send RCPT TO command and print server response.
rcptToCommand = 'RCPT To: macyali@gmail.com\r\n'
ssl_clientSocket.send(rcptToCommand)
recv3 = ssl_clientSocket.recv(1024)
print recv3

# If the first three numbers of the response from the server are not
# '250', we have a problem
if recv3[:3] != '250':
    print '250 reply not received from server.'

# Send DATA command and print server response.
dataCommand = 'DATA\r\n'
ssl_clientSocket.send(dataCommand)
recv4 = ssl_clientSocket.recv(1024)
print recv4

# If the first three numbers of the response from the server are not
# '250', we have a problem
if recv4[:3] != '250':
    print '250 reply not received from server.'

# Send message data.
ssl_clientSocket.send(msg)

# Message ends with a single period.
ssl_clientSocket.send(endmsg)

# Send QUIT command and get server response.
quitCommand = 'QUIT\r\n'
ssl_clientSocket.send(quitCommand)
recv5 = ssl_clientSocket.recv(I1024)
print recv5

# If the first three numbers of the response from the server are not
# '250', we have a problem
if recv5[:3] != '221':
    print '221 reply not received from server.'

2条回答
狗以群分
2楼-- · 2020-02-12 22:08
 recv5 = ssl_clientSocket.recv(I1024) 

has a I in the port number, is this causing you the issue? Or have you fixed that part already?

查看更多
小情绪 Triste *
3楼-- · 2020-02-12 22:23

You're connecting to port 587, which is the port for STARTTLS. When using SMTPS (ie. wrapping the socket before any other communication), you need to connect to port 465 instead of port 587. If you use STARTTLS, you wrap the socket later, after using the STARTTLS command and receiving a 220 response to it. After doing STARTTLS, you're supposed to do HELO again, since the server is supposed to forget anything that happened before the STARTTLS.

In either case, the servers at smtp.google.com ports 465 and 587 still won't return a 250 response to the MAIL command, since they require that you are authenticated before you send mail. You'll get a 530 response instead. You'll need to use the AUTH command with your gmail.com credentials to authenticate before you can use MAIL successfully on those servers.

If you don't want to authenticate, and depending on the details of what you need to do, you could try using port 25 of the server found in gmail.com's MX record. At the moment, the server is gmail-smtp-in.l.google.com and supports STARTTLS.

查看更多
登录 后发表回答