• socket通信原理?10分钟掌握python socket实现邮件客户端吧!


    1.系统功能设计

    创建一个向任何接收方发送电子邮件的简单邮件客户。你的客户将必须与邮件服务器(如谷歌的电子邮件服务器)创建一个TCP连接,使用SMTP协议与该邮件服务器进行交谈,经该邮件服务器向某接收方(如你的朋友)发送一个电子邮件报文,最后关闭与该邮件服务器的TCP连接。

    2.系统功能流程图

    3.系统功能实现测试

    系统实现一个SMTP客户端,使用QQ邮箱作为发件人,向指定的QQ邮箱发送一封邮件。SMTP协议即简单邮件传输协议,允许用户按照标准发送/接收邮件。

    流程如下:

    1.建立TCP连接并域服务器交互

    图3

    如图3所示qq邮件服务器建立连接,域名"smtp.qq.com",SMTP默认端口号25。建立连接后服务器将返回状态码220;与服务器的交互:发送"HELO"命令,开始与服务器的交互,服务器将返回状态码250(请求动作正确完成)。

    2.验证身份

    发送"AUTH LOGIN"命令,开始验证身份,服务器将返回状态码334(服务器等待用户输入验证信息)。发送经过base64编码的用户名,服务器等待用户输入验证信息,将返回状态码334。发送经过base64编码的密码(不是登录密码,而是开启SMTP时的授权码),用户验证成功,服务器将返回状态码235如图4所示。

    图4

    3.邮件传送

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

    endMsg = "\r\n.\r\n"

    # 选择一个邮件服务

    mailServer = "smtp.qq.com"

    # 发送方地址和接收方地址,from 和 to

    fromAddress = "2485947593@qq.com"

    toAddress = "3050387300@qq.com"

    图5

    连接建立并且验证成功后,就可开始传送邮件。邮件的传送从MAIL FROM命令开始,MAIL 命令后面有发件人的地址。MAIL FROM: 2485947593@qq.com。若SMTP服务器已准备好接收邮件,则回答250 OK。接着SMTP客户端发送一个或多个RCPT (收件人recipient的缩写)命令,格式为RCPT TO: <3050387300@qq.com>。每发送一个 RCPT命令,都应有相应的信息从SMTP服务器返回。正常情况下,SMTP服务器回复信息是354 Start mail input; end with . 。表示回车换行。此时SMTP客户端就可开始传送邮件内容,并用. (两个回车,中间一个点)表示邮件内容的结束。

    4.连接释放

    邮件发送完毕后,SMTP客户应发送QUIT命令。SMTP服务器返回的信息是221 (服务关闭),表示SMTP同意释放TCP连接。邮件传送的全部过程就此结束。同时,我们还可以登陆邮箱,查看邮件收发情况如图6、7所示

    图6

    图7

     4.源码

    1. # SMTPClient.py
    2. from socket import *
    3. msg = "\r\n I love computer networks!"
    4. endMsg = "\r\n.\r\n"
    5. # 选择一个邮件服务
    6. mailServer = "smtp.qq.com"
    7. # 发送方地址和接收方地址,from 和 to
    8. fromAddress = "2485947593@qq.com"
    9. toAddress = "3050387300@qq.com"
    10. # 发送方,验证信息,由于邮箱输入信息会使用base64编码,因此需要进行编码
    11. username = "MjQ4NTk0NzU5M0BxcS5jb20="  # 输入自己的用户名对应的编码
    12. password = "ZHRobnlvZmVyZGZsZWFpYg=="  # 此处不是自己的密码,而是开启SMTP服务时对应的授权码dthnyoferdfleaib
    13. # 创建客户端套接字并建立连接
    14. serverPort = 25  # SMTP使用25号端口
    15. clientSocket = socket(AF_INET, SOCK_STREAM)
    16. clientSocket.connect((mailServer, serverPort))  # connect只能接收一个参数
    17. # 从客户套接字中接收信息
    18. recv = clientSocket.recv(1024).decode()
    19. print(recv)
    20. if '220' != recv[:3]:
    21. print('220 reply not received from server.')
    22. # 发送 HELO 命令并且打印服务端回复
    23. # 开始与服务器的交互,服务器将返回状态码250,说明请求动作正确完成
    24. heloCommand = 'HELO Alice\r\n'
    25. clientSocket.send(heloCommand.encode())  # 随时注意对信息编码和解码
    26. recv1 = clientSocket.recv(1024).decode()
    27. print(recv1)
    28. if '250' != recv1[:3]:
    29. print('250 reply not received from server.')
    30. # 发送"AUTH LOGIN"命令,验证身份.服务器将返回状态码334(服务器等待用户输入验证信息)
    31. clientSocket.sendall('AUTH LOGIN\r\n'.encode())
    32. recv2 = clientSocket.recv(1024).decode()
    33. print(recv2)
    34. if '334' != recv2[:3]:
    35. print('334 reply not received from server.')
    36. # 发送验证信息
    37. clientSocket.sendall((username + '\r\n').encode())
    38. recvName = clientSocket.recv(1024).decode()
    39. print(recvName)
    40. if '334' != recvName[:3]:
    41.     print('334 reply not received from server')
    42. clientSocket.sendall((password + '\r\n').encode())
    43. recvPass = clientSocket.recv(1024).decode()
    44. print(recvPass)
    45. # 如果用户验证成功,服务器将返回状态码235
    46. if '235' != recvPass[:3]:
    47.     print('235 reply not received from server')
    48. # TCP连接建立好之后,通过用户验证就可以开始发送邮件。邮件的传送从MAIL命令开始,MAIL命令后面附上发件人的地址。
    49. # 发送 MAIL FROM 命令,并包含发件人邮箱地址
    50. clientSocket.sendall(('MAIL FROM: <' + fromAddress + '>\r\n').encode())
    51. recvFrom = clientSocket.recv(1024).decode()
    52. print(recvFrom)
    53. if '250' != recvFrom[:3]:
    54. print('250 reply not received from server')
    55. # 接着SMTP客户端发送一个或多个RCPT (收件人recipient的缩写)命令,格式为RCPT TO: <收件人地址>。
    56. # 发送 RCPT TO 命令,并包含收件人邮箱地址,返回状态码 250
    57. clientSocket.sendall(('RCPT TO: <' + toAddress + '>\r\n').encode())
    58. recvTo = clientSocket.recv(1024).decode()  # 注意UDP使用sendto,recvfrom
    59. print(recvTo)
    60. if '250' != recvTo[:3]:
    61. print('250 reply not received from server')
    62. # 发送 DATA 命令,表示即将发送邮件内容。服务器将返回状态码354(开始邮件输入,以"."结束)
    63. clientSocket.send('DATA\r\n'.encode())
    64. recvData = clientSocket.recv(1024).decode()
    65. print(recvData)
    66. if '354' != recvData[:3]:
    67. print('354 reply not received from server')
    68. # 编辑邮件信息,发送数据
    69. subject = "I love computer networks!"
    70. contentType = "text/plain"
    71. message = 'from:' + fromAddress + '\r\n'
    72. message += 'to:' + toAddress + '\r\n'
    73. message += 'subject:' + subject + '\r\n'
    74. message += 'Content-Type:' + contentType + '\t\n'
    75. message += '\r\n' + msg
    76. clientSocket.sendall(message.encode())
    77. # 以"."结束。请求成功返回 250
    78. clientSocket.sendall(endMsg.encode())
    79. recvEnd = clientSocket.recv(1024).decode()
    80. print(recvEnd)
    81. if '250' != recvEnd[:3]:
    82. print('250 reply not received from server')
    83. # 发送"QUIT"命令,断开和邮件服务器的连接
    84. clientSocket.sendall('QUIT\r\n'.encode())
    85. clientSocket.close()

    附:了解SMTP协议(简单邮件传输协议)常见命令和响应

    命令:

    HELO——发送端的主机信息

    MAIL FROM——发件人

    RCPT TO—— 收件人,可以有多个

    DATA——邮件主体内容

    QUIT——断开连接

    VRFY—— 需要对收件人名字进行验证

    EXPN——需要扩展的邮件发送清单

    HELP——命令名

    响应:

    220——服务器就绪

    221——服务关闭

    421——服务器未就绪,关闭传输信道

    250——要求的邮件操作完成

    501——参数格式错误

  • 相关阅读:
    深度思考rpc框架面经之五:rpc限流:rpc事务:tps测试
    Vue+iview将表格table以excel文件导出的几种方式
    F#奇妙游(31):数据缺失的处理
    【论文整理1】On the Continuity of Rotation Representations in Neural Networks
    学会这几个PPT制作技巧,让同事对你刮目相看
    构建Docker基础镜像(ubuntu20.04+python3.9.10+pytorch-gpu-cuda11.8)
    火山引擎徐鑫:工程师如何与云原生共同成长
    Qt5开发及实例V2.0-第七章-Qt图形视图框架
    自定义类型详解(保姆级教程)
    Linux服务器被入侵后的排查思路(应急响应思路)
  • 原文地址:https://blog.csdn.net/wzkwzk1/article/details/133215412