python 工资邮件群发工具开发(一个小公司的需求)

------------------------------------

该需求有两个表格,第一个表格是计算薪资的,第二个表格是员工信息,包括姓名和邮箱

这里只要把薪资表按照每个人截图放到一个文件夹中,从信息表取姓名和截图名字做对应,然后发送邮件,企业邮箱和qq邮箱均可,返回日志文件XXX.log

 1、工资表样式,名字必须和员工信息表一致

 

2、员工信息表样式注意列,我没有做行列自定义选择的功能,现在是写死的,当然也可以加个变量自定义

 

软件样式:

 

 

 

本程序是根据员工信息表的基础,来判定是否成功发送邮件,如果工资表没有这个人,那么也没有这个人的截图,那这个人就未发送。

 授权码就是qq邮箱的 第三方授权

 --------------------------------------------------

用到的包pillow 、xlwings、email、tkinter(界面UI)

-----------------------------------

这里不多废话,直接贴代码

  1 from PIL import ImageGrab
  2 import xlwings as xw
  3 import smtplib
  4 from email.mime.multipart import MIMEMultipart
  5 from email.mime.text import MIMEText
  6 from email.mime.image import MIMEImage
  7 import tkinter as tk  # 使用Tkinter前需要先导入
  8 from tkinter import filedialog
  9 import os
 10 import datetime
 11 
 12 class Monitor():
 13     def __init__(self):
 14         #错误信息
 15         self.error = []
 16         self.nosend = []
 17         self.dictname =[]
 18         #发送完成信息
 19         self.succcees =''
 20 
 21     #判断文件夹是否已经创建
 22     def is_exists(self,dir):
 23         if not os.path.exists(dir):
 24             os.makedirs(dir)
 25     #日志函数
 26     def  log(self,excel_name):
 27         path = './'+str(datetime.datetime.now())[:-16]+'.log'
 28         with open(path,'a+') as f:
 29             f.write(str(datetime.datetime.now())[:-7] +' '+ excel_name+'\n')
 30             f.write('     发送成功人员:'+self.succcees+'\n')
 31 
 32     # 截图函数
 33     def excel_catch_screen(self,wbs,save_floder,shot_sheetname):
 34         sheet = wbs.sheets(shot_sheetname)  # 选定sheet
 35         all = sheet.used_range  # 获取有内容的range
 36         all.api.CopyPicture()  # 复制图片区域
 37         sheet.api.Paste()  # 粘贴
 38         pic = sheet.pictures[0]  # 当前图片
 39         pic.api.Copy()  # 复制图片
 40         img = ImageGrab.grabclipboard()  # 获取剪贴板的图片数据
 41         self.is_exists(save_floder)  # 判断文件夹
 42         try:
 43             img.save(save_floder+'/'+shot_sheetname + ".png")  # 保存图片
 44             pic.delete()  # 删除sheet上的图片
 45         except:
 46             print('%s 截图失败!'%shot_sheetname)
 47 
 48     #   邮件函数
 49     #   1、查看邮件excel中的所有对应值  (name,email)
 50     def get_info(self,dicts,info):
 51         app = xw.App(visible=False, add_book=False)
 52         wb = app.books.open(info)
 53         sheet = wb.sheets[0]
 54         maxrow = sheet.used_range.last_cell.row   # 最大行
 55         for row in range(2,maxrow+1):
 56             name = sheet.range('B' + str(row)).value
 57             email = str(sheet.range('J' + str(row)).value).replace('@qq.com','')
 58             dicts[name] = email.replace('.0','')+'@qq.com'
 59         wb.close()
 60         app.quit()
 61     #2、发送邮件
 62     def send_png(self,subject,sender,name,receivers,password,png):
 63         message = MIMEMultipart('related')
 64         message['Subject'] = subject
 65         message['From'] = sender
 66         message['To'] = receivers
 67         content = MIMEText('<html><body><img src="cid:imageid" alt="imageid"></body></html>','html','utf-8')
 68         message.attach(content)
 69         file=open(png, "rb")
 70         img_data = file.read()
 71         file.close()
 72         img = MIMEImage(img_data)
 73         img.add_header('Content-ID', 'imageid')
 74         message.attach(img)
 75         try:
 76             if(sender[-6:] == 'qq.com'):
 77                 server=smtplib.SMTP_SSL("smtp.qq.com",465)
 78             else:
 79                 server=smtplib.SMTP_SSL("smtp.exmail.qq.com",465)
 80             server.login(sender,password) #"填写qq邮箱的授权码"
 81             server.sendmail(sender,receivers,message.as_string())
 82             server.quit()
 83             print ("邮件发送成功")
 84             self.succcees+=name+','
 85         except smtplib.SMTPException as e:
 86             self.error.append(name)
 87             print(e)
 88 
 89     def work(self,subject,sender,password,excel_name,info_name):
 90         sheetname=[]
 91         app = xw.App(visible=False, add_book=False)
 92         wb = app.books.open(excel_name)
 93         num = len(wb.sheets)
 94         #用sheetname 接受所有员工的sheet名
 95         for i in range(1,num):
 96             sheet = wb.sheets[i]
 97             sheetname.append(sheet.name)
 98         #循环截屏并保存到自定义文件夹下
 99         save_floder = './'+subject
100         for name in sheetname:
101             self.excel_catch_screen(wb,save_floder,name)
102         #存储员工信息表
103         dicts = {}
104         self.get_info(dicts,info_name)
105 
106         wb.close()  # 不保存,直接关闭
107         app.quit()
108         #循环发送邮件 #发送邮件 根据excel中的邮件人姓名和地址进行匹配已保存的png图片,顺序发送
109         # 遍历字典,在文件夹中找对应图片
110         for name, receivers in dicts.items():
111             self.dictname.append(name)
112         for file in os.listdir(save_floder):
113             self.nosend.append(file.replace('.png',''))
114         for name, receivers in dicts.items():
115             if name in self.nosend:
116                 self.send_png(subject,sender,name,receivers,password,save_floder+'/'+name+'.png')
117                 print(sender,receivers,name,save_floder+'/'+name+'.png')
118             else:
119                 self.error.append(name)
120 
121     def main(self):
122         # 界面化处理
123         window = tk.Tk()
124         window.title('邮件群发V1.0')
125         # 第3步,设定窗口的大小(长 * 宽)
126         window.geometry('400x400')  # 这里的乘是小x
127 
128         def selectPath():
129             entry_excel_name = filedialog.askopenfilename(title='选择工资计算表',
130                       initialdir='/', filetypes=[('.xlsx','*.xlsx'),('全部文件','*.*')])
131             return entry_excel_name
132         def selectPath1():
133             entry_info_name = filedialog.askopenfilename(title='选择员工信息表',
134                       initialdir='/', filetypes=[('.xlsx','*.xlsx'),('全部文件','*.*')])
135             return entry_info_name
136 
137         def exec(entry_excel_name,entry_info_name):
138             try:
139                 subject = entry_title.get()
140                 sender = entry_usr_name.get()
141                 password = entry_usr_pwd.get()
142                 excel_name = entry_excel_name
143                 info_name = entry_info_name
144 
145                 print("请等待...")
146                 self.work(subject,sender,password,excel_name,info_name)
147                 print("生成日志文件完成,若要查看,请移步当前文件夹下logs")
148                 self.log(excel_name)
149 
150                 if len(self.error) == 0:
151                     text.insert('insert','所有邮件发送成功')
152                 else:
153                     text.insert('insert','%s 邮件发送失败' % self.error)
154             except Exception as e:
155                 if e == 'No such file: ':
156                     text.insert('insert','没有选择文件')
157                 else:
158                     text.insert('insert',e)
159 
160         # 用户信息
161         tk.Label(window, text='邮件标题:', font=('Arial', 10)).place(x=10, y=5)
162         tk.Label(window, text='Q Q 号:', font=('Arial', 10)).place(x=10, y=35)
163         tk.Label(window, text='授权码:', font=('Arial', 10)).place(x=10, y=65)
164 
165         subject = tk.StringVar()
166         subject.set('XX年XX月薪资')
167         entry_title = tk.Entry(window, textvariable=subject, font=('Arial', 10))
168         entry_title.place(x=120, y=5)
169 
170         var_usr_name = tk.StringVar()
171         var_usr_name.set('XXXX邮箱')
172         entry_usr_name = tk.Entry(window, textvariable=var_usr_name, font=('Arial', 10))
173         entry_usr_name.place(x=120, y=35)
174 
175         var_usr_pwd = tk.StringVar()
176         var_usr_pwd.set('XXXX授权码')
177         entry_usr_pwd = tk.Entry(window, textvariable=var_usr_pwd, font=('Arial', 10), show='*')
178         entry_usr_pwd.place(x=120, y=65)
179 
180         #程序运行框
181         text = tk.Text(window, show=None)
182         text.place(relx=0.01,rely=0.3,relwidth=0.98,relheight=0.7)
183 
184         # 执行按钮
185         btn_login = tk.Button(window, text='立即执行',height = 4,  width = 15 ,command= lambda : exec(selectPath(),selectPath1()))
186         btn_login.place(x=275, y=6)
187 
188         # 主窗口循环显示
189         window.mainloop()
190 
191 if __name__ == '__main__':
192     app = Monitor()
193     app.main()

 

posted @ 2022-03-10 11:04  欲乘风上云霄  阅读(168)  评论(0编辑  收藏  举报