更新时间:2020-02-28 11:10
在编写RPA流程时,我们经常需要在流程中收发邮件,而最常用的收发邮件方式是使用SMTP和POP3,下面我们来说明一下如何在RPA中收发邮件。
SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。
python的smtplib提供了一种很方便的途径发送电子邮件。它对smtp协议进行了简单的封装。
Python创建 SMTP 对象语法如下:
import smtplib
smtpObj = smtplib.SMTP( [host [, port [, local_hostname]]] )
参数说明:
Python SMTP 对象使用 sendmail 方法发送邮件,语法如下:
SMTP.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options])
参数说明:
这里要注意一下第三个参数,msg 是字符串,表示邮件。我们知道邮件一般由标题,发信人,收件人,邮件内容,附件等构成,发送邮件的时候,要注意 msg 的格式。这个格式就是 smtp 协议中定义的格式。
使用脚本发送邮件的思路其实和客户端发送邮件一样,过程都是:登录 —> 写邮件 —> 发送
只不过通过脚本发送时我们需要考虑到整个过程的方方面面。以下为思路导图:
基本思路是:
另外在发送简单文本邮件时,我们需要使用 MIMEText 类作为邮件主体。
from rpa.core import *
from rpa.utils import *
import rpa3 as rpa # 使用V3引擎
import smtplib
from email.mime.text import MIMEText
def start():
# 设置登录及服务器信息
# 邮箱服务器地址
mail_host = 'smtp.xxxx.com'
# 邮件用户名,这里我们推荐使用RPA的云变量(资产变量)存储敏感信息
mail_user = rpa.asset.value("mail_user")
# 密码(部分邮箱为授权码) ,这里我们推荐使用RPA的云变量(资产变量)存储敏感信息
mail_password = rpa.asset.value("mail_password")
# 邮件发送方邮箱地址
sender = 'xxxx@xxxx.com'
# 邮件接受方邮箱地址,注意这里是一个列表<list>,这意味着你可以写多个邮件地址群发
receivers = ['xxxx@xxxx.com']
# 设置email信息
# 邮件内容设置
message = MIMEText('使用RPA测试邮件发送','plain','utf-8')
# 邮件主题
message['Subject'] = '邮件测试'
# 发送方信息
message['From'] = sender
# 接受方信息
message['To'] = receivers[0]
# 登录并发送邮件
try:
smtpObj = smtplib.SMTP_SSL()
# 连接到服务器
smtpObj.connect(mail_host, 465)
# 登录到服务器
smtpObj.login(mail_user, mail_password)
# 发送
smtpObj.sendmail(
sender, receivers, message.as_string())
# 退出
smtpObj.quit()
print('success')
except smtplib.SMTPException as e:
print('error',e) # 打印错误
一些邮箱登录比如阿里企业邮箱、QQ 邮箱需要 SSL 认证,所以 SMTP 已经不能满足要求,而需要SMTP_SSL,解决办法为:
smtpObj = smtplib.SMTP()
smtpObj.connect(mail_host, 25)
#######替换为########
smtpObj = smtplib.SMTP_SSL()
smtpObj.connect(mail_host, 465) # 注意要修改端口号
常用邮箱端口说明:
邮箱 | SMTP服务器 | SSL协议端口 | 非SSL协议端口 |
---|---|---|---|
163 | smtp.163.com | 465或者994 | 25 |
smtp.qq.com | 465或587 | 25 |
基本思路就是,使用MIMEMultipart来标示这个邮件是多个部分组成的,然后attach各个部分。如果是附件,则add_header加入附件的声明。
在python中,MIME的这些对象的继承关系如下。
MIMEBase
|— MIMENonMultipart
|— MIMEApplication
|— MIMEAudio
|— MIMEImage
|— MIMEMessage
|— MIMEText
|— MIMEMultipart
一般来说,不会用到MIMEBase,而是直接使用它的继承类。MIMEMultipart有attach方法,而MIMENonMultipart没有,只能被attach。MIME有很多种类型,这个略麻烦,如果附件是图片格式,我要用MIMEImage,如果是音频,要用MIMEAudio,如果遇到word、excel等我们不确定该用哪种MIME类型时,可以不管什么类型的附件,都用MIMEApplication,MIMEApplication默认子类型是application/octet-stream。
application/octet-stream表明“这是个二进制的文件,希望对端那边知道怎么处理”,然后客户端,比如阿里企业邮箱,收到这个声明后,会根据文件扩展名来猜测。
from rpa.core import *
from rpa.utils import *
import rpa3 as rpa # 使用V3引擎
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.mime.application import MIMEApplication
def start():
# 设置登录及服务器信息
# 邮箱服务器地址
mail_host = 'smtp.xxxx.com'
# 邮件用户名,这里我们推荐使用RPA的云变量(资产变量)存储敏感信息
mail_user = rpa.asset.value("mail_user")
# 密码(部分邮箱为授权码) ,这里我们推荐使用RPA的云变量(资产变量)存储敏感信息
mail_password = rpa.asset.value("mail_password")
# 邮件发送方邮箱地址
sender = 'xxxx@xxxx.com'
# 邮件接受方邮箱地址,注意这里是一个列表<list>,这意味着你可以写多个邮件地址群发
receivers = ['xxxx@xxxx.com']
# 设置eamil信息
# 添加一个MIMEmultipart类,处理正文及附件
message = MIMEMultipart()
message['From'] = sender
message['To'] = receivers[0]
message['Subject'] = '邮件测试'
# ---这是文字部分---
# 推荐使用html格式的正文内容,这样比较灵活,可以附加图片地址,调整格式等
with open(r'C:\temp\测试HTML.html','rb') as hf:
html_content = hf.read()
# 设置html格式参数
html_part = MIMEText(html_content,'html','utf-8')
message.attach(html_part)
# ---这是附件部分---
# 添加一个txt文本附件
with open(r'C:\temp\测试文本.txt','rb') as tf:
txt_content = tf.read()
txt_part = MIMEApplication(txt_content)
txt_part.add_header('Content-Disposition', 'attachment', filename="测试.txt")
message.attach(txt_part)
# 添加一个xlsx类型附件
with open(r'C:\temp\测试Excel.xlsx','rb') as ef:
excle_content = ef.read()
excle_part = MIMEApplication(excle_content)
excle_part.add_header('Content-Disposition', 'attachment', filename="测试Excel.xlsx")
message.attach(excle_part)
# 添加一个docx类型附件
with open(r'C:\temp\测试word.docx','rb') as df:
word_content = df.read()
word_part = MIMEApplication(word_content)
word_part.add_header('Content-Disposition', 'attachment', filename="测试word.docx")
message.attach(word_part)
# 添加一个pdf类型附件
with open(r'C:\temp\测试PDF.pdf','rb') as pf:
pdf_content = pf.read()
pdf_part = MIMEApplication(pdf_content)
pdf_part.add_header('Content-Disposition', 'attachment', filename="测试PDF.pdf")
message.attach(pdf_part)
# 添加一个png类型附件
with open(r'C:\temp\测试图片.png','rb') as gf:
png_content = gf.read()
png_part = MIMEApplication(png_content)
png_part.add_header('Content-Disposition', 'attachment', filename="测试图片.png")
message.attach(png_part)
# 登录并发送
try:
smtpObj = smtplib.SMTP_SSL()
# 连接到服务器
smtpObj.connect(mail_host, 465)
# 登录到服务器
smtpObj.login(mail_user, mail_password)
# 发送
smtpObj.sendmail(
sender, receivers, message.as_string())
# 退出
smtpObj.quit()
print('success')
except smtplib.SMTPException as e:
print('error',e)
POP3和IMAP
POP是指邮局协议,目的是让用户可以访问邮箱服务器中的邮件,允许用户从服务器上把邮件存储到本地主机(即自己的计算机)上,同时删除保存在邮件服务器上的邮件,而POP3服务器则是遵循POP3协议的接收邮件服务器,用来接收电子邮件的。
后来又出现了IMAP协议(Interactive Mail Access Protocol),即交互式邮件访问协议,与POP3的不同在于:开启了IMAP后,在电子邮件客户端收取的邮件仍然保留在服务器上,同时在客户端上的操作都会反馈到服务器上,如:删除邮件,标记已读等,服务器上的邮件也会做相应的动作
python的poplib模块支持POP3,基本步骤:
poplib的常用方法:
方法 | 描述 |
---|---|
POP3(server) | 实例化POP3对象,server是pop服务器地址 |
user(username) | 发送用户名到服务器,等待服务器返回信息 |
pass_(password) | 密码 |
stat() | 返回邮箱的状态,返回2元祖(消息的数量,消息的总字节) |
list([msgnum]) | stat()的扩展,返回一个3元祖(返回信息, 消息列表, 消息的大小),如果指定msgnum,就只返回指定消息的数据 |
retr(msgnum) | 获取详细msgnum,设置为已读,返回3元组(返回信息, 消息msgnum的所以内容, 消息的字节数),如果指定msgnum,就只返回指定消息的数据 |
dele(msgnum) | 将指定消息标记为删除 |
quit() | 登出,保存修改,解锁邮箱,结束连接,退出 |
from poplib import POP3
p = POP3('pop.xxxx.com')
p.user('xxxx@xxxx.com')
p.pass_('xxxxxxxx')
p.stat()
...
p.quit()
python中的imaplib包支持IMAP4
常用方法:
方法 | 描述 |
---|---|
IMAP4(server) | 与IMAP服务器建立连接 |
login(user, pass) | 用户密码登录 |
list() | 查看所有的文件夹(IMAP可以支持创建文件夹) |
select() | 选择文件夹默认是”INBOX” |
search() 三个参数,第一的是CHARSET,通常为None(ASCII),第二个参数不知到是干什么官方没解释 |
import getpass, imaplib
M = imaplib.IMAP4()
M.login(getpass.getuser(), getpass.getpass())
M.select()
typ, data = M.search(None, 'ALL')
for num in data[0].split():
typ, data = M.fetch(num, '(RFC822)')
print('Message %s\n%s\n' % (num, data[0][1]))
M.close()
M.logout()
在文档使用中是否遇到以下问题
更多建议
匿名提交