老婆大人最近提出一个需求,从事人资的她每个季度都要跟近期合同到期的人续签合同。续签合同需要提前准备好带有每个人信息的确认函发邮件给其领导签字确认要续约,然后邮件咨询对应员工其信息有无变化和意愿,最后生成相应的续约合同。希望这个过程能够自动化,输入就只是一份近期合同到期人员的excel。
这个当然不难,以前老婆有用过OFFICE自带的邮件合并功能。但是只能自动生成一个含有一大帮确认函和续约合同的大WORD,不能自动生成PDF,也不能自动发规定格式的邮件。
对于Python来说,这个不算复杂,把一些现成的库粘到一起就好,主要用到docxtpl,docx2pdf,pandas,beautifulsoup.
1.excel到WORD/PDF
pandas用来读excel里的信息,这个相对简单,核心代码如下。这里只读了一个数,实际上后面要用到的参数都可以这里读。
df = pd.read_excel(infofilepath)
for i in range(df.shape[0]):
HODFullName = df.at[i, 'HOD']#读取excel第i+1行HOD列的数据(第1行是列名)
docxtpl可以修改word模板中的变量,跟邮件合并功能类似。核心代码如下。
from docxtpl import DocxTemplate
import docx2pdf
doc = DocxTemplate("Renewal of Labor Contract-Format.docx")
context={'Today':todaystr,'HODFullName':HODFullName,'HODName':HODName,'ECName':ecname,
'EEName':eename,'ENumber':enumber,'ENEndDate':eenddate,'EFBeginDate':efbegindate,'EFEndDate':efenddate}
doc.render(context)
savefilename = "劳动合同续订意见征求书_" + df.at[i, '英文名字'] + ".docx"
doc.save(savefilename)
docx2pdf.convert(savefilename)
time.sleep(1)
WORD里就是这个样子的模板,注意花括号和变量名中间是有个空格的。
docxtpl还有很多丰富的功能,可以自动生成更复杂的表格、黏贴图片等等功能。详见其官方说明。
https://docxtpl.readthedocs.io/en/latest/
docx2pdf倒是非常简单,就是把word自动转为PDF。主要的问题就是速度比较慢,一篇1页的东西要转换2-8秒,不知道为啥这么慢。
2. EXCEL到OUTLOOK
如果邮件的格式要求比较复杂,要粘附件,有表格,有签字等信息。我摸索的方法是先在OUTLOOK写一份模板,另存为HTML文件。把里面的关键段落标识改掉,比如开头的Dear Peter改为“领导敬语”。由于OUTLOOK默认搞出来的HTML中每种不同的字体/格式或者分段后多会出来个<span>***</span>。包括表格里复杂的信息也一样。所以可以用beautifulsoup把span全找出来,一个个对着改。关键代码如下。
beautifulsoup里get_text()方法可以提取各种标签的文字,然后用if或者正则都行来改东西,这样格式不会变。改完后用sp.string那行就把值赋值了。这里这写了关键代码,其他流程性代码根据需要补全。
from bs4 import BeautifulSoup
import win32com.client as win32
outlook = win32.Dispatch('Outlook.Application')
mail_item = outlook.CreateItem(0) # 0: olMailItem
mail_item.Recipients.Add(hodmail)#增加收件人
mail_item.Subject = "Labor Contract Renewal (expire on"+eenddate+" ) - "+eename#邮件标题
current_dir = os.path.dirname(os.path.abspath(__file__))
print(current_dir+"\\劳动合同续订意见征求书_" + df.at[i, '英文名字'] + ".pdf")
mail_item.Attachments.Add(current_dir+"\\劳动合同续订意见征求书_" + df.at[i, '英文名字'] + ".pdf")#增加邮件附件
mail_item.BodyFormat = 2 # 2: Html format
htmlfile = open("test.html", 'r', encoding='utf-8')
htmlhandle = htmlfile.read()
tplbody=BeautifulSoup(htmlhandle,features="lxml")
spans=tplbody.find_all('span')
for sp in spans:
if sp.get_text()=="经理敬语":
sp.string="Dear "+HODName+","
mail_item.HTMLBody = tplbody.prettify(formatter="html")#把beautifulsoup处理的HTML信息导入OUTLOOK
accounts=outlook.Session.Accounts#获取OUTLOOK账号列表
for account in accounts:
#print(account.DisplayName)
if(account.DisplayName=="youwant@yourcompany.com"):
addrEntry=account.CurrentUser.AddressEntry
mail_item.Sender=addrEntry#设置发件人,如果Outlook里只有一个账号一个发件人这段可以省略
#mail_item.Display()#显示邮件效果,如果不看就发就省略
mail_item.Send()#发送邮件
Outlook的发送依赖于用pywin32直接调用COM操作OUTLOOK,所以相关的属性或方法得查MSDN。
https://docs.microsoft.com/zh-cn/office/vba/api/overview/outlook
Outlook的HTML部分见下图
3.问题
总得来说比较成功,Outlook可以自动发邮件,粗体、表格、表格背景颜色等都按照老婆要求保留了。也可以自动附上需要的根据员工信息生成的PDF文件。
但是在移植到老婆电脑的时候遇上问题。。。。pyinstaller和py2exe都没能成功打包,都提示缺库,搞不定。。。
目前反正把excel和模板拷到我电脑上,然后在我电脑上Outlook登录她账号也行,就先这么凑合用,等我啥时候搞明白为啥打包不不成功再去她电脑搞。
最后吐槽一句,为啥现在各大传统公司一搞信息安全就不给装Python。。。VBA和.NET的资源太少了。。。希望MS尽快官方支持把VBA改成Python。