Background
最近业务需求需要把生成的月报定时发送到指定邮箱,直接在网上找了相关经验改巴改巴给实现了,测试可以直接使用,生产是我从MySQL数据库获取文件信息和邮箱等使用的,程序中的注释相当清楚了。定时是通过shell脚本实现的。
获取邮件服务器和授权码
PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取
源码
from datetime import datetime
from pymysql import connect
import smtplib
from email.header import Header
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
# 【mysql 基本信息】
class MysqlUtil:
# 定义基本属性【测试】
host = '110.110.110.110'
username = 'wlf'
password = 'wlf'
database = 'wlf'
charset = 'utf8'
# 定义基本属性【生产】
# host = '192.168.110.110'
# username = 'wlf'
# password = 'wlf'
# database = 'wlf'
# charset = 'utf8'
# 定义构造方法
def __init__(self):
self.connection = None
self.cursor = None
# 初始化 MySQL 连接配置
try:
self.connection = connect(host=self.host, user=self.username, password=self.password,
database=self.database, charset=self.charset)
self.cursor = self.connection.cursor()
except():
print("mysql connect failed, please check the config")
# 获取所有需要发送月报的项目以及对应的邮箱,返回字典结构,key为项目id,value为list,存储邮箱
def get_projects_with_emails(self):
table = 'cft_report_email'
pid_email_dict = {}
sql_projects = "SELECT `project_id`, `email` FROM %s" % table
self.cursor.execute(sql_projects)
res_pid_email = self.cursor.fetchall()
for pe in res_pid_email:
pid = pe[0]
email = pe[1]
if pid in pid_email_dict:
pid_email_dict[pid].append(email)
else:
email_list = [email]
pid_email_dict[pid] = email_list
return pid_email_dict
# 根据项目id和月报时间获取月报路径
def get_filepath(self, pid):
table = 'report_month'
last_month_date = get_last_month_date()
sql = "SELECT `path` FROM %s WHERE project_id = '%s' AND `report_date` = '%s'" % (table, pid, last_month_date)
self.cursor.execute(sql)
res_path = self.cursor.fetchone()[0]
return res_path
# 获取上月日期 年份和月份 例子:2020年10月
def get_last_month_date():
now_month = datetime.now()
year = now_month.year
month = now_month.month
if month == 1:
month = 12
year -= 1
else:
month -= 1
return str(year) + "年" + str(month) + "月"
# 向指定邮箱发送文件
def send_email(file, emails):
"""
发送邮件的脚本,在邮件中可添加text文本,图片和附件
:return:
"""
# 设置服务器(这里是163的服务器,这里需要用户名和密码,host网上查对应的smtp服务器)
mail_host = "smtp.163.com"
mail_user = "yunluwlf@163.com"
# 密码(这里的密码不是登录邮箱密码,而是授权码)
mail_auth_code = "IXMHKCCISDRJGVJW"
# 邮件发送和接收人
sender = mail_user
reciever = emails
# 邮件头信息
message = MIMEMultipart('related')
message['From'] = sender
message['To'] = ','.join(reciever)
message['Subject'] = Header('数据简报【输电铁塔】')
# ③图片 形式的内容添加到邮件(包含在②中,否咋上传的是图片附件)
# fp = open(r'D:/wkspc/pycharm-wkspc/wind_rose/imgs/2020-10/ybj/wind-rose.jpg', 'rb')
# content_image = MIMEImage(fp.read())
# fp.close()
# content_image.add_header('content-disposition', 'attachment', filename='wind-rose.jpg')
# message.attach(content_image)
# ④ 附件 形式的内容添加到邮件
attach_table = MIMEApplication(open(file, 'rb').read())
attach_table.add_header('content-disposition', 'attachment', filename=get_file_name(file))
# 这样的话,附件名称就可以是中文的了,不会出现乱码
attach_table.set_charset('utf-8')
message.attach(attach_table)
# 发送邮件,测试成功,流程都是固定的:创建客户端,登陆,发送,关闭
try:
# 实例化
smtpObj = smtplib.SMTP()
# 25为 SMTP 端口号
smtpObj.connect(mail_host, 25)
smtpObj.login(mail_user, mail_auth_code)
print('登录成功!')
smtpObj.sendmail(mail_user, reciever, message.as_string())
smtpObj.quit()
print("恭喜:邮件发送成功!")
except smtplib.SMTPException:
print("错误:邮件发送失败!")
# 根据文件路径获取文件名
def get_file_name(file_path):
splits = file_path.split("/")
return splits[len(splits) - 1]
if __name__ == '__main__':
# 【测试】
file_send = 'docs/results/2020年10月/羊八井测点2020年10月风场实测数据简报.docx'
emails_to_send = ['1147314023@qq.com', 'longfei.wang@cloudansys.com']
send_email(file_send, emails_to_send)
# 【生产】
# 获取MySQL工具类对象
# mysql_util = MysqlUtil()
# # 获取所有需要发送月报的项目id以及对应的邮箱
# dict_pid_with_email = mysql_util.get_projects_with_emails()
# # 获取所有需要发送月报的项目id
# dict_keys = dict_pid_with_email.keys()
# for project_id in dict_keys:
# # 根据项目id获取获取发送的月报路径
# the_filepath = mysql_util.get_filepath(project_id)
# # 获取项目id对应的邮箱
# the_email_list = dict_pid_with_email[project_id]
# # 向对应的邮箱发送邮件
# send_email(the_filepath, the_email_list)
效果
注意
经测试:支持网易邮箱和qq邮箱;不支持搜狐邮箱。
ps:其实搜狐邮箱也能发送成功,但是发过去的时候文件不知怎么被改名改后缀了,变成了`投递状态.txt`,当然,如果手动把txt改成docx还是可以打开文件的,内容也没变。
12