发送邮件可以用smtp协议,整个过程为:
用户代理(user-agent,比如outlook、foxmail等邮件客户端)---(smtp协议)--->本地邮件服务器 --- (smtp协议)---> 远程邮件服务器 --- (imap,pop3或http协议)--->远程客户代理(收取邮件)
其中本地邮件服务器和远程邮件服务器是直通式,一般不经过中转,如果远程邮件服务器没开启等原因导致发送失败那么过一段时间后重复发送。这是本地邮件服务器的职责。
smtp是应用层协议,下面需要tcp协议支撑。smtp报文作为tcp报文的数据部分进行传输。因此我们自行创建TCP socket,并将smtp报文作为数据,塞到tcp socket中进行发送。
smtp报文的构造,根据协议,包括MAIL FROM, RCPT TO, DATA, . ,QUIT等部分。构造起来不复杂。
最后一个子问题是获取邮件服务器的地址。通过nslookup -qt=mx xxx.com来获取,比如nslookup -qt=mx 163.com得到163mx02.mxmail.netease.com,端口一般是25。
那么接下来就是code
#coding:utf-8from socket import *msg = "\r\n I love computer networks!" #需要发送的数据endmsg = "\r\n.\r\n"# Choose a mail server (e.g. Google mail server) and call it mailservermailserver = ("163mx02.mxmail.netease.com",25) #Fill in start #Fill in end# Create socket called clientSocket and establish a TCP connection with mailserver#Fill in startclientSocket = socket(AF_INET, SOCK_STREAM)clientSocket.connect(mailserver)#Fill in endrecv = clientSocket.recv(1024)print 'recv:',recvif recv[:3] != '220': print '220 reply not received from server.'# Send HELO command and print server response.heloCommand = 'HELO Alice\r\n'clientSocket.send(heloCommand)recv1 = clientSocket.recv(1024)print 'recv1:',recv1if recv1[:3] != '250': print '250 reply not received from server.'# Send MAIL FROM command and print server response.# Fill in startfromCommand = "MAIL FROM:\r\n" #匿名邮件的「发送人」,可以随意伪造clientSocket.send(fromCommand)recv2 = clientSocket.recv(1024)print 'recv2:', recv2# Fill in end# Send RCPT TO command and print server response.# Fill in starttoCommand = "RCPT TO: \r\n" #收件人地址。clientSocket.send(toCommand)recv3 = clientSocket.recv(1024)print 'recv3:', recv3# Fill in end# Send DATA command and print server response.# Fill in startdataCommand = "DATA\r\n"clientSocket.send(dataCommand)recv4 = clientSocket.recv(1024)print 'recv4:', recv4# Fill in end# Send message data.# Fill in startclientSocket.send(msg)# Fill in end# Message ends with a single period.# Fill in startclientSocket.send(endmsg)# Fill in end# Send QUIT command and get server response.# Fill in startquitCommand = "QUIT\r\n"clientSocket.send(quitCommand)recv5 = clientSocket.recv(1024)print 'recv5:', recv5# Fill in endclientSocket.close()
注意如果邮件找不到,可能归类到垃圾邮件了。一个解决办法是把邮件内容数据(msg)加密后再发送。
ref:《计算机网络:自顶向下方法》第6版 第二章 套接字编程作业3 邮件客户