Python进阶篇(五)-- 邮件客户端实现与电子邮件发送

2023-11-02 12:30

本文主要是介绍Python进阶篇(五)-- 邮件客户端实现与电子邮件发送,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 SMTP

        通过完成本实验,我们将更加了解SMTP协议。还将学到使用Python实现标准协议的经验。

        主要任务是开发一个简单的邮件客户端,将邮件发送给任意收件人。客户端将需要连接到邮件服务器,使用SMTP协议与邮件服务器进行对话,并向邮件服务器发送电子邮件。 Python提供了一个名为smtplib的模块,它内置了使用SMTP协议发送邮件的方法。但是我们不会在本实验中使用此模块,因为它隐藏了SMTP和套接字编程的细节。

        为了限制垃圾邮件,一些邮件服务器不接受来源随意的TCP连接。对于下面所述的实验,您可能需要尝试连接到您的大学邮件服务器和流行的Webmail服务器(如AOL邮件服务器)。您也可以尝试从您的家和您的大学校园进行连接。

        这里采用qq邮箱来完成。本文将实现一个SMTP客户端,使用qq邮箱作为发件人,向指定的163邮箱发送一封邮件。

        SMTP协议即简单邮件传输协议,允许用户按照标准发送/接收邮件。

        在本文中,SMTP邮件客户端程序的基本流程如下:

  1. 与qq邮件服务器建立TCP连接,域名"smtp.qq.com",SMTP默认端口号25。建立连接后服务器将返回状态码220,代表服务就绪(类似HTTP,SMTP也使用状态码通知客户端状态信息)。
  2. 发送"HELO"命令,开始与服务器的交互,服务器将返回状态码250(请求动作正确完成)。
  3. 发送"AUTH LOGIN"命令,开始验证身份,服务器将返回状态码334(服务器等待用户输入验证信息)。
  4. 发送经过base64编码的用户名(本例中是163邮箱的账号),服务器将返回状态码334(服务器等待用户输入验证信息)。
  5. 发送经过base64编码的密码(本例中是163邮箱的密码),服务器将返回状态码235(用户验证成功)。
  6. 发送"MAIL FROM"命令,并包含发件人邮箱地址,服务器将返回状态码250(请求动作正确完成)。
  7. 发送"RCPT TO"命令,并包含收件人邮箱地址,服务器将返回状态码250(请求动作正确完成)。
  8. 发送"DATA"命令,表示即将发送邮件内容,服务器将返回状态码354(开始邮件输入,以"."结束)。
  9. 发送邮件内容,服务器将返回状态码250(请求动作正确完成)。
  10. 发送"QUIT"命令,断开与邮件服务器的连接。

1.2 代码实现

# -*- encoding: utf-8 -*-
# @Author: CarpeDiem
# @Date: 230504
# @Version: 1.0
# @Description: Python 实现邮件客户端from socket import *
import base64# Mail content
subject = "I love computer networks!"
contenttype = "text/plain"
msg = "I love computer networks!"
endmsg = "\r\n.\r\n"# Choose a mail server (e.g. Google mail server) and call it mailserver 
mailserver = "smtp.qq.com"# Sender and reciever
fromaddress = "xxxxxxxxx@qq.com"
toaddress = "xxxxx@163.com"# Auth information (Encode with base64)
username = "xxxxxxxxx@qq.com"
password = "xxxxxxxxxxx"username = base64.b64encode(username.encode()).decode()
password = base64.b64encode(password.encode()).decode()# Create socket called clientSocket and establish a TCP connection with mailserver
clientSocket = socket(AF_INET, SOCK_STREAM) 
clientSocket.connect((mailserver, 25))recv = clientSocket.recv(1024).decode()
print(recv)
if recv[:3] != '220':print('220 reply not received from server.')# Send HELO command and print server response.
heloCommand = 'HELO CarpeDiem\r\n'
clientSocket.send(heloCommand.encode())
recv1 = clientSocket.recv(1024).decode()
print(recv1)
if recv1[:3] != '250':print('250 reply not received from server.')# Auth
clientSocket.sendall('AUTH LOGIN\r\n'.encode())
recv = clientSocket.recv(1024).decode()
print(recv)
if (recv[:3] != '334'):print('334 reply not received from server')clientSocket.sendall((username + '\r\n').encode())
recv = clientSocket.recv(1024).decode()
print(recv)
if (recv[:3] != '334'):print('334 reply not received from server')clientSocket.sendall((password + '\r\n').encode())
recv = clientSocket.recv(1024).decode()
print(recv)
if (recv[:3] != '235'):print('235 reply not received from server')# Send MAIL FROM command and print server response.
clientSocket.sendall(('MAIL FROM: <' + fromaddress + '>\r\n').encode())
recv = clientSocket.recv(1024).decode()
print(recv)
if (recv[:3] != '250'):print('250 reply not received from server')# Send RCPT TO command and print server response.
clientSocket.sendall(('RCPT TO: <' + toaddress + '>\r\n').encode())
recv = clientSocket.recv(1024).decode()
print(recv)
if (recv[:3] != '250'):print('250 reply not received from server')# Send DATA command and print server response.
clientSocket.send('DATA\r\n'.encode())
recv = clientSocket.recv(1024).decode()
print(recv)
if (recv[:3] != '354'):print('354 reply not received from server')# Send message data.
message = 'from:' + fromaddress + '\r\n'
message += 'to:' + toaddress + '\r\n'
message += 'subject:' + subject + '\r\n'
message += 'Content-Type:' + contenttype + '\t\n'
message += '\r\n' + msg
clientSocket.sendall(message.encode())# Message ends with a single period.
clientSocket.sendall(endmsg.encode())
recv = clientSocket.recv(1024).decode()
print(recv)
if (recv[:3] != '250'):print('250 reply not received from server')# Send QUIT command and get server response.
clientSocket.sendall('QUIT\r\n'.encode())# Close connection
clientSocket.close()

        温馨提示: 有些邮箱默认关闭SMTP服务,比如本文使用的qq邮箱。需要在设置中打开SMTP服务。另外,qq邮箱在打开SMTP服务后,会设置一个授权码,在程序使用这个授权码作为密码登录,而不是平时使用的密码。

        一切正常的话,运行效果如下图所示,将会看到服务器返回的每条消息,其中包含每次操作后返回的状态码。

        同时,我们还可以登陆发件人邮箱和收件人邮箱,在发件人的已发送文件夹中和收件人的收件箱中都能看到这封被发送的邮件。左图为qq邮箱,右图为网易163邮箱。


2 网络应用开发

2.1 发送电子邮件

        在即时通信软件如此发达的今天,电子邮件仍然是互联网上使用最为广泛的应用之一,公司向应聘者发出录用通知、网站向用户发送一个激活账号的链接、银行向客户推广它们的理财产品等几乎都是通过电子邮件来完成的,而这些任务应该都是由程序自动完成的。

        就像我们可以用HTTP(超文本传输协议)来访问一个网站一样,发送邮件要使用SMTP(简单邮件传输协议),SMTP也是一个建立在TCP(传输控制协议)提供的可靠数据传输服务的基础上的应用级协议,它规定了邮件的发送者如何跟发送邮件的服务器进行通信的细节,而Python中的smtplib模块将这些操作简化成了几个简单的函数。

        smtplib和email,这俩模块是Python自带的,只需import即可使用。smtplib模块主要负责发送邮件,email模块主要负责构造邮件。

  • smtplib模块主要负责发送邮件:是一个发送邮件的动作,连接邮箱服务器,登录邮箱,发送邮件(有发件人,收信人,邮件内容)。
  • email模块主要负责构造邮件:指的是邮箱页面显示的一些构造,如发件人,收件人,主题,正文,附件等。

代码说明:

  1. smtplib模块

smtplib.SMTP()              # 实例化SMTP()login(user, password)
# user:登录邮箱的用户名。
# password:登录邮箱的密码,像笔者用的是网易邮箱,网易邮箱一般是网页版,需要用到客户端密码,需要在网页版的网易邮箱中设置授权码,该授权码即为客户端密码。sendmail(from_addr, to_addrs, msg,)
# from_addr:邮件发送者地址
# to_addrs:邮件接收者地址。字符串列表[‘接收地址1’,‘接收地址2’,‘接收地址3’,…]
# msg:发送消息:邮件内容。一般是msg.as_string():as_string()是将msg(MIMEText对象或者MIMEMultipart对象)变为str。quit()      # 用于结束SMTP会话。

2) email模块

        email模块下有mime包,mime英文全称为“Multipurpose Internet Mail Extensions”,即多用途互联网邮件扩展,是目前互联网电子邮件普遍遵循的邮件技术规范。

        该mime包下常用的有三个模块:text, image, multpart。

        导入方法如下:

from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header

        构造一个邮件对象就是一个Message对象,如果构造一个MIMEText对象,就表示一个文本邮件对象,如果构造一个MIMEImage对象,就表示一个作为附件的图片,要把多个对象组合起来,就用MIMEMultipart对象,而MIMEBase可以表示任何对象。它们的继承关系如下:

Message
+- MIMEBase+- MIMEMultipart+- MIMENonMultipart+- MIMEMessage+- MIMEText+- MIMEImage

        下面的代码演示了如何在Python发送普通的文字邮件。

1. 发送普通文字邮件

# -*- encoding: utf-8 -*-
# @Author: CarpeDiem
# @Date: 230428
# @Version: 1.0
# @Description: Python 发送邮件from smtplib import SMTP_SSL
from email.header import Header 
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipartdef main():# 设定邮件发送者和接受者host_server = 'smtp.qq.com'             # qq 邮箱smtp服务器sender = 'xxxxxxxx@qq.com'              # 发件人邮箱pwd = 'xxxxxxxxxxxxx'receivers = ['xxxxxxx@gmail.com', 'xxxxxx@163.com']              # 收件人邮箱mail_title = "Python自动发送的邮件"                               # 邮件标题  mail_content = "您好,这是使用python登录QQ邮箱发送邮件的测试——xq"   # 邮件正文内容message = MIMEMultipart()               # 初始化一个邮件主体message['Subject'] = Header(mail_title, 'utf-8')message['From'] = sendermessage['To'] = ";".join(receivers)message.attach(MIMEText(mail_content, 'plain', 'utf-8'))    # 邮件正文内容smtper = SMTP_SSL(host_server)      # ssl登录# login(user,password):# user:登录邮箱的用户名。# password:登录邮箱的密码,这里用的是QQ邮箱,# 需要用到客户端密码,需要在QQ邮箱中设置授权码,该授权码即为客户端密码smtper.login(sender, pwd)smtper.sendmail(sender, receivers, message.as_bytes())print("邮件发送完成!")# quit(): 用于结束SMTP会话smtper.quit()if __name__ == '__main__':main()

2. 发送html格式邮件

# -*- encoding: utf-8 -*-
# @Author: CarpeDiem
# @Date: 230419
# @Version: 1.0
# @Description: Python 发送HTML格式邮件import smtplib
from smtplib import SMTP_SSL
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Headerhost_server = "smtp.qq.com"             # qq邮箱smtp服务器
sender_qq = "xxxxxxx@qq.com"         # 发件人邮箱
password = "xxxxxxxxxxxx"           # 授权码
receiver = "xxxxxxx@163.com"
mail_title = "Python自动发送html格式的邮件" # 邮件标题
# 邮件正文内容
mail_content = "您好!<p>这是使用python登录QQ邮箱发送\HTNL格式邮件的测试:</p> <p>\<a href='https://blog.csdn.net/xq151750111?spm=1010.2135.3001.5421'>CSDN个人主页</a></p>"msg = MIMEMultipart()
msg["Subject"] = Header(mail_title, "utf-8")
msg["From"] = sender_qq
msg["To"] = Header("测试邮箱", "utf-8")msg.attach(MIMEText(mail_content, 'html'))try:smtp = SMTP_SSL(host_server)    # ssl登录连接到邮件服务器smtp.set_debuglevel(True)       # False to disable debugsmtp.ehlo(host_server)          # 跟服务器打招呼,告诉它我们准备连接smtp.login(sender_qq, password)smtp.sendmail(sender_qq, receiver, msg.as_string())smtp.quit()print("邮件发送成功")
except smtplib.SMTPException:print("无法发送邮件")

3. 发送带附件的邮件

# -*- encoding: utf-8 -*-
# @Author: CarpeDiem
# @Date: 230419
# @Version: 1.0
# @Description: Python 发送HTML格式邮件以及附件import string
import smtplib
from smtplib import SMTP_SSL
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.mime.application import MIMEApplication  # 用于添加附件host_server = "smtp.qq.com"             # qq邮箱smtp服务器
sender_qq = "xxxxxxx@qq.com"         # 发件人邮箱
password = "xxxxxxxxxxxx"           # 授权码
receiver = "xxxxxxxx@163.com"
mail_title = "Python自动发送html格式的邮件" # 邮件标题
# 邮件正文内容
mail_content = "您好!<p>这是使用python登录QQ邮箱发送\HTNL格式邮件的测试:</p> <p>\<a href='https://blog.csdn.net/xq151750111?spm=1010.2135.3001.5421'>CSDN个人主页</a></p>"msg = MIMEMultipart()
msg["Subject"] = Header(mail_title, "utf-8")
msg["From"] = sender_qq
msg["To"] = Header("测试邮箱", "utf-8")msg.attach(MIMEText(mail_content, 'html'))
attachment = MIMEApplication(open("H:\\毕业设计\\LassoNet\\脑区选择.xlsx", 'rb').read())
attachment["Content-Type"] = "application/octet-stream"# 给附件重命名
basename = "test.xlsx"
attachment.add_header('Content-Disposition', 'attachment', filename=('utf-8', '', basename))
msg.attach(attachment)try:smtp = SMTP_SSL(host_server)    # ssl登录连接到邮件服务器smtp.set_debuglevel(True)       # False to disable debugsmtp.ehlo(host_server)          # 跟服务器打招呼,告诉它我们准备连接smtp.login(sender_qq, password)smtp.sendmail(sender_qq, receiver, msg.as_string())smtp.quit()print("邮件发送成功")
except smtplib.SMTPException:print("无法发送邮件")

2.2 发送短信

        发送短信也是项目中常见的功能,网站的注册码、验证码、营销信息基本上都是通过短信来发送给用户的。在下面的代码中我们使用了互亿无线短信平台(该平台为注册用户提供了50条免费短信以及常用开发语言发送短信的demo,可以登录该网站并在用户自服务页面中对短信进行配置)提供的API接口实现了发送短信的服务,当然国内的短信平台很多,读者可以根据自己的需要进行选择(通常会考虑费用预算、短信达到率、使用的难易程度等指标),如果需要在商业项目中使用短信服务建议购买短信平台提供的套餐服务。

import urllib.parse
import http.client
import jsondef main():host  = "106.ihuyi.com"sms_send_uri = "/webservice/sms.php?method=Submit"# 下面的参数需要填入自己注册的账号和对应的密码params = urllib.parse.urlencode({'account': 'API ID', 'password' : 'API KEY', 'content': '您的验证码是:666888。请不要把验证码泄露给其他人。', 'mobile': 'xxxxxxxxx', 'format':'json' })print(params)headers = {'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain'}conn = http.client.HTTPConnection(host, port=80, timeout=30)conn.request('POST', sms_send_uri, params, headers)response = conn.getresponse()response_str = response.read()jsonstr = response_str.decode('utf-8')print(json.loads(jsonstr))conn.close()if __name__ == '__main__':main()

        详细了解,请阅读:短信验证码/通知 - API文档


参考

  • Python实现自动发送邮件(详解):https://blog.csdn.net/weixin_44827418/article/details/111255414
  • Python网络应用开发:https://gitee.com/zengyujin/Python-100-Days/blob/master/Day01-15/14.%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E5%85%A5%E9%97%A8%E5%92%8C%E7%BD%91%E7%BB%9C%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91.md#%E7%BD%91%E7%BB%9C%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91

这篇关于Python进阶篇(五)-- 邮件客户端实现与电子邮件发送的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/330614

相关文章

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P