python使用tkinter&pandas&smtplib读取Excel并发送邮件
#### 1. 功能介绍:
当然是因为15号发工资啦,每次都是等呀等呀等呀等呀,最后终于等到一张来自Excel的工资条截图
于是我就希望能够学以致用试试,但是写好了又不敢给领导看~哈哈哈,发给大家批评批评
首先,需要一个Excel咯,这里我用的office2019,如果是旧版本的文件就看第60行注释
软件功能就是,可以读取一个Excel文件并将每一条信息发送到相应的邮箱中
要发送的信息很方便改动
2. python代码:
这里将html代码和python分开放了,显得没那么臃肿,使用的时候将24行字符串填进去即可
import _thread
import smtplib
import webbrowser
from email.header import Header
from email.mime.text import MIMEText
from tkinter import *
from tkinter import filedialog, messagebox
import pandas as pd
class App:
# 全部
all_info: int = 0
# 发送失败
err_info: int = 0
# 发送成功
suc_info: int = 0
# 当前数据
t: pd.DataFrame = None
# 表示正在执行的邮件发送线程的数量
counter: int = 0
# html模板,为了防止打包打不进去,干脆写进来了
html: str = """"""
def __init__(self, _root):
self.root = _root
self.center_window()
# 布局
# line_0
self.path = StringVar()
# self.path.set("请将路径复制到此框或通过右边按钮选择路径")
self.path.set("C:/Users/xy/Desktop/工资.xlsx")
self.path_e = Entry(self.root, textvariable=self.path, width=72)
self.path_e.grid(row=0, column=0, columnspan=3, padx=5, pady=5)
self.path_button = Button(self.root, text='选择路径', command=self.select_path)
self.path_button.grid(row=0, column=3, padx=5, pady=5)
# line_1
self.info = Listbox(self.root, width=82)
self.info.grid(row=1, column=0, padx=5, pady=5, columnspan=4)
# line_2
self.show_table_b = Button(self.root, text='预览文件', command=self.show_table)
self.show_table_b.grid(row=2, column=1, padx=5, pady=5)
self.send_email_b = Button(self.root, text='发送邮件', command=self.send)
self.send_email_b.grid(row=2, column=2, padx=5, pady=5, sticky='w')
# line_3
self.msg = StringVar()
self.msg.set('邮件发送状态')
self.msb_l = Label(self.root, textvariable=self.msg)
self.msb_l.grid(row=3, column=0, columnspan=3, padx=5, pady=5, sticky='w')
# # 获取html模板
# with open('a.html', 'r') as f:
# self.html = f.read()
def select_path(self):
path_ = filedialog.askopenfilename(title='打开工资表', filetypes=[('Excel', '*.xlsx')])
# 如果要打开旧版本Excel文件,可以将下面这一行取消注释。顺便将上面一行注释掉。也可以自己写完整的文件后缀。
# path_ = filedialog.askopenfilename(title='打开工资表')
if path_ != "":
self.path.set(path_)
# 窗口居中,有bug,在电脑设置了“‘缩放与布局-->更改文本、应用等项目的大小’”不为100%时会有偏差。跟分辨率和像素有关,无心解决
def center_window(self, w=600, h=280):
ws = self.root.winfo_screenwidth()
hs = self.root.winfo_screenheight()
x = (ws // 2) - (w // 2)
y = (hs // 2) - (h // 2)
self.root.geometry(f'{w}x{h}+{x}+{y}')
# 就是通过浏览器读取一下Excel信息,应用空间很小,估计只有在电脑上没有安装Excel才能用到吧~
def show_table(self):
# 读Excel
if self.get_data():
return
self.all_info = self.t.index.size
self.t.to_html('a.html')
webbrowser.open('a.html')
# 读取并发送。
def send(self):
# 读Excel
if self.get_data():
return
self.all_info = self.t.index.size
# 防止按钮被点坏了
self.send_email_b['state'] = 'disable'
for index, row in self.t.iterrows():
# 多线程防止界面假死
_thread.start_new_thread(self.send_email, (row.values,))
# 发送邮件并更新状态
def send_email(self, data: list):
self.counter += 1
# 替换模板内容
html = self.html
for index, item in enumerate(data):
html = html.replace('{' + str(index) + '}', str(item))
receiver = data[-1]
# 发送邮箱的用户名和授权码(不是登录邮箱的密码)
username = 'tianxiezijideyouxiangzhanghao@qq.com'
password = 'haiyouzijidemima'
# 邮件主题
mail_title = '工资发放情况'
# 邮件内容, 格式, 编码
message = MIMEText(html, 'html', 'utf-8')
message['From'] = u'小言<' + username + '>'
message['To'] = receiver
message['Subject'] = Header(mail_title, 'utf-8')
try:
smtp = smtplib.SMTP()
smtp.connect('smtp.qq.com')
smtp.login(username, password)
smtp.sendmail(username, receiver, message.as_string())
smtp.quit()
state = '成功'
self.suc_info += 1
except smtplib.SMTPException as e:
state = str(e)
self.err_info += 1
# 添加状态
self.info.insert('end', data[0].ljust(10, '-') + receiver.ljust(25, '-') + state)
self.counter -= 1
if self.counter == 0:
self.send_email_b['state'] = 'normal'
# 更新信息
self.msg.set(
f'邮件发送状态:共计 {self.all_info} 条信息,'
f'已发送{self.suc_info + self.err_info}条,'
f'剩余{self.all_info - self.suc_info - self.err_info}条,'
f'其中成功发送{self.suc_info}条,'
f'失败{self.err_info}条')
def get_data(self):
try:
self.t = pd.read_excel(self.path.get())
self.t.fillna('', inplace=True)
return False
except Exception as e:
messagebox.showerror('出现异常', str(e))
return True
if __name__ == '__main__':
# 写的不规范,但是无奈不知道规范的怎么写~
root = Tk()
# 设置全局字体,在四处寻求无果后于百度知道找到了一位大佬在2011年写出的答案
root.option_add('*Font', 'Fira 10')
root.title('通过邮件发放工资表')
root.resizable(0, 0)
App(root)
root.mainloop()
import _thread
import smtplib
import webbrowser
from email.header import Header
from email.mime.text import MIMEText
from tkinter import *
from tkinter import filedialog, messagebox
import pandas as pd
class App:
# 全部
all_info: int = 0
# 发送失败
err_info: int = 0
# 发送成功
suc_info: int = 0
# 当前数据
t: pd.DataFrame = None
# 表示正在执行的邮件发送线程的数量
counter: int = 0
# html模板,为了防止打包打不进去,干脆写进来了
html: str = """"""
def __init__(self, _root):
self.root = _root
self.center_window()
# 布局
# line_0
self.path = StringVar()
# self.path.set("请将路径复制到此框或通过右边按钮选择路径")
self.path.set("C:/Users/xy/Desktop/工资.xlsx")
self.path_e = Entry(self.root, textvariable=self.path, width=72)
self.path_e.grid(row=0, column=0, columnspan=3, padx=5, pady=5)
self.path_button = Button(self.root, text='选择路径', command=self.select_path)
self.path_button.grid(row=0, column=3, padx=5, pady=5)
# line_1
self.info = Listbox(self.root, width=82)
self.info.grid(row=1, column=0, padx=5, pady=5, columnspan=4)
# line_2
self.show_table_b = Button(self.root, text='预览文件', command=self.show_table)
self.show_table_b.grid(row=2, column=1, padx=5, pady=5)
self.send_email_b = Button(self.root, text='发送邮件', command=self.send)
self.send_email_b.grid(row=2, column=2, padx=5, pady=5, sticky='w')
# line_3
self.msg = StringVar()
self.msg.set('邮件发送状态')
self.msb_l = Label(self.root, textvariable=self.msg)
self.msb_l.grid(row=3, column=0, columnspan=3, padx=5, pady=5, sticky='w')
# # 获取html模板
# with open('a.html', 'r') as f:
# self.html = f.read()
def select_path(self):
path_ = filedialog.askopenfilename(title='打开工资表', filetypes=[('Excel', '*.xlsx')])
# 如果要打开旧版本Excel文件,可以将下面这一行取消注释。顺便将上面一行注释掉。也可以自己写完整的文件后缀。
# path_ = filedialog.askopenfilename(title='打开工资表')
if path_ != "":
self.path.set(path_)
# 窗口居中,有bug,在电脑设置了“‘缩放与布局-->更改文本、应用等项目的大小’”不为100%时会有偏差。跟分辨率和像素有关,无心解决
def center_window(self, w=600, h=280):
ws = self.root.winfo_screenwidth()
hs = self.root.winfo_screenheight()
x = (ws // 2) - (w // 2)
y = (hs // 2) - (h // 2)
self.root.geometry(f'{w}x{h}+{x}+{y}')
# 就是通过浏览器读取一下Excel信息,应用空间很小,估计只有在电脑上没有安装Excel才能用到吧~
def show_table(self):
# 读Excel
if self.get_data():
return
self.all_info = self.t.index.size
self.t.to_html('a.html')
webbrowser.open('a.html')
# 读取并发送。
def send(self):
# 读Excel
if self.get_data():
return
self.all_info = self.t.index.size
# 防止按钮被点坏了
self.send_email_b['state'] = 'disable'
for index, row in self.t.iterrows():
# 多线程防止界面假死
_thread.start_new_thread(self.send_email, (row.values,))
# 发送邮件并更新状态
def send_email(self, data: list):
self.counter += 1
# 替换模板内容
html = self.html
for index, item in enumerate(data):
html = html.replace('{' + str(index) + '}', str(item))
receiver = data[-1]
# 发送邮箱的用户名和授权码(不是登录邮箱的密码)
username = 'tianxiezijideyouxiangzhanghao@qq.com'
password = 'haiyouzijidemima'
# 邮件主题
mail_title = '工资发放情况'
# 邮件内容, 格式, 编码
message = MIMEText(html, 'html', 'utf-8')
message['From'] = u'小言<' + username + '>'
message['To'] = receiver
message['Subject'] = Header(mail_title, 'utf-8')
try:
smtp = smtplib.SMTP()
smtp.connect('smtp.qq.com')
smtp.login(username, password)
smtp.sendmail(username, receiver, message.as_string())
smtp.quit()
state = '成功'
self.suc_info += 1
except smtplib.SMTPException as e:
state = str(e)
self.err_info += 1
# 添加状态
self.info.insert('end', data[0].ljust(10, '-') + receiver.ljust(25, '-') + state)
self.counter -= 1
if self.counter == 0:
self.send_email_b['state'] = 'normal'
# 更新信息
self.msg.set(
f'邮件发送状态:共计 {self.all_info} 条信息,'
f'已发送{self.suc_info + self.err_info}条,'
f'剩余{self.all_info - self.suc_info - self.err_info}条,'
f'其中成功发送{self.suc_info}条,'
f'失败{self.err_info}条')
def get_data(self):
try:
self.t = pd.read_excel(self.path.get())
self.t.fillna('', inplace=True)
return False
except Exception as e:
messagebox.showerror('出现异常', str(e))
return True
if __name__ == '__main__':
# 写的不规范,但是无奈不知道规范的怎么写~
root = Tk()
# 设置全局字体,在四处寻求无果后于百度知道找到了一位大佬在2011年写出的答案
root.option_add('*Font', 'Fira 10')
root.title('通过邮件发放工资表')
root.resizable(0, 0)
App(root)
root.mainloop()
3. html代码
<!-- Row Highlight Javascript -->
<script>
window.onload = function () {
var tfrow = document.getElementById('tfhover').rows.length;
var tbRow = [];
for (var i = 1; i < tfrow; i++) {
tbRow[i] = document.getElementById('tfhover').rows[i];
tbRow[i].onmouseover = function () {
this.style.backgroundColor = '#ffffff';
};
tbRow[i].onmouseout = function () {
this.style.backgroundColor = '#f0c169';
};
}
};
</script>
<style type="text/css">
table.tftable {
font-size: 12px;
color: #333333;
width: 100%;
border-width: 1px;
border-color: #ebab3a;
border-collapse: collapse;
}
table.tftable th {
font-size: 12px;
background-color: #e6983b;
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #ebab3a;
text-align: left;
}
table.tftable tr {
background-color: #f0c169;
}
table.tftable td {
font-size: 12px;
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #ebab3a;
}
</style>
<table id="tfhover" class="tftable" border="1">
<tr>
<th>姓名</th>
<th>岗级</th>
<th>考勤小计</th>
<th>岗位工资,绩效奖金</th>
<th>餐补</th>
<th>出差补助</th>
<th>司龄</th>
<th>学历</th>
<th>证书</th>
<th>话补</th>
<th>地区补贴</th>
<th>C奖金</th>
<th>B奖金</th>
<th>A奖金</th>
<th>D奖金</th>
<th>E奖金</th>
<th>F奖金</th>
<th>工资扣款</th>
<th>应发工资</th>
<th>社保</th>
<th>公积金</th>
<th>个税</th>
<th>实发工资</th>
<th>邮箱</th>
</tr>
<tr>
<td>{0}</td>
<td>{1}</td>
<td>{2}</td>
<td>{3}</td>
<td>{4}</td>
<td>{5}</td>
<td>{6}</td>
<td>{7}</td>
<td>{8}</td>
<td>{9}</td>
<td>{10}</td>
<td>{11}</td>
<td>{12}</td>
<td>{13}</td>
<td>{14}</td>
<td>{15}</td>
<td>{16}</td>
<td>{17}</td>
<td>{18}</td>
<td>{19}</td>
<td>{20}</td>
<td>{21}</td>
<td>{22}</td>
<td>{23}</td>
</tr>
</table>
<!-- Row Highlight Javascript -->
<script>
window.onload = function () {
var tfrow = document.getElementById('tfhover').rows.length;
var tbRow = [];
for (var i = 1; i < tfrow; i++) {
tbRow[i] = document.getElementById('tfhover').rows[i];
tbRow[i].onmouseover = function () {
this.style.backgroundColor = '#ffffff';
};
tbRow[i].onmouseout = function () {
this.style.backgroundColor = '#f0c169';
};
}
};
</script>
<style type="text/css">
table.tftable {
font-size: 12px;
color: #333333;
width: 100%;
border-width: 1px;
border-color: #ebab3a;
border-collapse: collapse;
}
table.tftable th {
font-size: 12px;
background-color: #e6983b;
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #ebab3a;
text-align: left;
}
table.tftable tr {
background-color: #f0c169;
}
table.tftable td {
font-size: 12px;
border-width: 1px;
padding: 8px;
border-style: solid;
border-color: #ebab3a;
}
</style>
<table id="tfhover" class="tftable" border="1">
<tr>
<th>姓名</th>
<th>岗级</th>
<th>考勤小计</th>
<th>岗位工资,绩效奖金</th>
<th>餐补</th>
<th>出差补助</th>
<th>司龄</th>
<th>学历</th>
<th>证书</th>
<th>话补</th>
<th>地区补贴</th>
<th>C奖金</th>
<th>B奖金</th>
<th>A奖金</th>
<th>D奖金</th>
<th>E奖金</th>
<th>F奖金</th>
<th>工资扣款</th>
<th>应发工资</th>
<th>社保</th>
<th>公积金</th>
<th>个税</th>
<th>实发工资</th>
<th>邮箱</th>
</tr>
<tr>
<td>{0}</td>
<td>{1}</td>
<td>{2}</td>
<td>{3}</td>
<td>{4}</td>
<td>{5}</td>
<td>{6}</td>
<td>{7}</td>
<td>{8}</td>
<td>{9}</td>
<td>{10}</td>
<td>{11}</td>
<td>{12}</td>
<td>{13}</td>
<td>{14}</td>
<td>{15}</td>
<td>{16}</td>
<td>{17}</td>
<td>{18}</td>
<td>{19}</td>
<td>{20}</td>
<td>{21}</td>
<td>{22}</td>
<td>{23}</td>
</tr>
</table>
最后是Excel表格的样式,我就不上传文件了,反正没有具体的特殊要求
姓名 | 岗级 | 考勤小计 | 岗位工资,绩效奖金 | 餐补 | 出差补助 | 司龄 | 学历 | **证书 | 话补 | 地区补贴 | A奖 | B奖 | C奖 | D奖 | E奖 | F奖 | 工资扣款 | 应发工资 | 社保 | 公积金 | 个税 | 实发工资 | 邮箱 |
小言 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 3293232930@qq.com |
凉云 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 3293232930@qq.com |
2019-05-17 08:40 凉云