email.py
import os
import argparse
import yaml
import smtplib
import csv
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from urllib import unquote
import logging
import logging.handlers logger = logging.getLogger()
error_list = []
all_error_file_list=[] def extension(filename):
"""
get file extension
:param filename:
:return:
"""
ext = os.path.splitext(filename)[1]
if ext.startswith('.'):
# os.path.splitext retains . separator
ext = ext[1:]
return ext def list_file(file_name, list):
"""
get all failed file list ,contains sub folder
:param file_name: file name or folder name
:param list:
:return:
"""
if os.path.isdir(file_name):
for s in os.listdir(file_name):
list_file(os.path.join(file_name, s), list)
else:
ext = extension(file_name)
if ext == "failed":
list.append(file_name) def read_email_record(faild_path):
"""
read last failed file record
:param faild_path:
:return:
"""
record = os.path.join(faild_path, "email_record.txt")
if not os.path.isfile(record):
return {}
try:
return yaml.load(open(record))
except Exception as err:
return {} def rewrite_record(args):
"""
save record file
:param args:
:return:
"""
if not error_list:
return
record = os.path.join(args.failed_path, "email_record.txt")
map = {}
for s in all_error_file_list:
map[s] = "emailed"
f = open(record, "w")
yaml.dump(map, f, default_flow_style=False)
f.close() def process(args):
"""
process :
* list all failed files
* read record list
* remove duplicate data
:param args:
:return:
"""
faild_path = args.failed_path
if not os.path.isdir(faild_path):
logger.error("failed path:%s is not exist, exist", faild_path)
return
list_file(faild_path, all_error_file_list)
record_map = read_email_record(faild_path)
if not record_map:
error_list.extend(all_error_file_list)
else:
for file in all_error_file_list:
if not record_map.has_key(file):
error_list.append(file) def generate_body(s3path):
"""
generate email body
:return:
"""
body = """<h4>The following billing csv files are format failed,please check</h4>
"""
logger.info("failed file list as below:")
# list all failed list which need send email
for s in error_list:
# define line number from 0
line_num = 0
# to get error file name and path , just support {orgid}/{failed_file} format
ps = os.path.split(s)
# to regenerate new web path, such as s3://{bucket}/xxx/{orgid}/{fail_file}
s3 = os.path.join(s3path, os.path.split(ps[0])[1], ps[1])
# generate html body
body += "<hr>"
# add file name with link
body += """<div>File: <a href="%s">%s<a></div>""" % (s3, ps[1])
# add URL which can copy
body += "<div>URL: %s</div>" % (s3)
# add logger info
logger.info("-"*50)
logger.info("file:[%s]",s)
# lines which read each time
total_rows_each_read=10000000
# open failed file
with open(s, 'r') as f:
# read file in loop
while 1:
# get lines array list
lines = f.readlines(total_rows_each_read)
if not lines:
break
# check each line with csv , when failed ,
# generate new array from failed index and re-check until finished
while len(lines)>0:
# check csv format with strict = True
reader=csv.reader(lines, strict=True)
# define array index
i = 0
try:
# get rows of each line
for row in reader:
# when row is csv format , array index will ++
i += 1
line_num += 1
for item in row:
# check each column whether with \n , if yes ,will add line number
if str(item).find('\n')>0:
i += 1
line_num += 1
# when all lines is correct , array will set to empty to break loop
lines=[]
# get Exceptions
except Exception as err:
# when error occur , line number will increase 1
line_num += 1
#line_num += reader.line_num
line = lines[i]
# generate each error line information
body += "<div></div><br><br>"
body += "<li><div>Error line number: [#%s] </div></li>" \
"<div>#Exceptions: [%s]</div>" % (line_num, err)
body += """<div>#Error row data as below:</div>
<div>%s</div>""" % line
if (i+1) == len(lines):
lines=[]
else:
tmp=lines[i+1:]
lines = tmp
body += "<hr>"
return body def email_sender(args):
"""
send email ,iterator each receiver then send email
:param args:
:return:
"""
subject = "Error Pipeline CSV File List"
#if not error_list:
# return False
#body = generate_body(args.s3url)
body = "test"
emails = args.email
smtp_host = args.smtpHost
smtp_port = args.smtpPort
username = args.username
password = args.password
sent_from = args.sentFrom if emails:
mail_server = smtplib.SMTP()
try:
msg = MIMEMultipart()
msg['From'] = sent_from
msg['Subject'] = subject
msg.attach(MIMEText(body, 'html'))
mail_server.connect(smtp_host, smtp_port)
mail_server.ehlo()
mail_server.starttls()
mail_server.ehlo()
if password and smtp_host != 'eng-smtp.calix.local':
mail_server.login(username, unquote(password))
for recipient in emails:
logger.info("send email to %s", recipient)
msg['To'] = recipient
mail_server.sendmail(sent_from, recipient, msg.as_string())
except Exception as err:
logger.error("send email failed:%s", err)
return False
finally:
if mail_server:
mail_server.close()
return True
return False def init_log(log_file):
"""
init logger
:param log_file:
:return:
"""
log_path = os.path.split(log_file)[0]
if not os.path.isdir(log_path):
os.makedirs(log_path)
logger.setLevel(logging.DEBUG)
handler = logging.handlers.RotatingFileHandler(log_file,
maxBytes=20 * 1024 * 1024,
backupCount=5,
)
fmt = '%(asctime)s-[%(filename)s:%(lineno)s]-[%(levelname)s]- %(message)s'
formatter = logging.Formatter(fmt)
handler.setFormatter(formatter)
logger.addHandler(handler) def main():
parser = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('--failed_path', default='/var/tmp/billing/', help='store failed files')
parser.add_argument('-e', '--email', action='append',
help="To send multiple emails --email <email-address-1> --email <email-address-2> ...")
parser.add_argument('--smtpHost', type=str, help="Host of SMTP server", required=False,
default="outlook.office365.com")
parser.add_argument('--smtpPort', type=int, help="Port of SMTP server", required=False, default=587)
parser.add_argument('--username', type=str, help="outlook username", required=False)
parser.add_argument('--password', type=str, help="outlook password", required=False)
parser.add_argument('--sentFrom', type=str, help="outlook email", required=False,
default="noreply-compass-fa@calix.com")
parser.add_argument('--logfile', help='logger file name', required=False,
default='/var/log/sxadp-api-server/scan_failed_email.log')
parser.add_argument('--s3url',type=str,help="billing s3 URL ",required=False)
args = parser.parse_args()
init_log(args.logfile)
#process(args)
if email_sender(args):
print "done"
#rewrite_record(args) if __name__ == '__main__':
main()
email.py的更多相关文章
- Python遇到ModuleNotFoundError: No module named 'email.mime'; 'email' is not a package问题的处理办法
写Python的时候我们会遇到如下的错误: Traceback (most recent call last): File "F:/exploitation/codes/python/Jet ...
- 新建py文件时取名千万要小心 不要和已有模块重名
这是因为我新建了一个email.py的文件 后来我将文件名rename成了myemail.py没有看改名提示,结果导致所有的对email的import和调用全部改成了对myemail的import和调 ...
- Python 程序员经常犯的 10 个错误
关于PythonPython是一种解释性.面向对象并具有动态语义的高级程序语言.它内建了高级的数据结构,结合了动态类型和动态绑定的优点,这使得... 关于Python Python是一种解释性.面向对 ...
- Python开发最常犯错误总结10种
不管是在学习还是工作过程中,人都会犯错.虽然Python的语法简单.灵活,但也一样存在一些不小的坑,一不小心,初学者和资深Python程序员都有可能会栽跟头.本文是Toptal网站的程序员梳理的10大 ...
- Python程序的常见错误(收集篇)
关于Python Python是一门解释性的,面向对象的,并具有动态语义的高级编程语言.它高级的内置数据结构,结合其动态类型和动态绑定的特性,使得它在快速应用程序开发(Rapid Applicatio ...
- flask 程序结构概括
以此结构为例,这个小项目是<Flask Web开发:基于python的web应用开发实战>第一部分结束后的代码框架 第一层 有app.tests.migrations三个文件夹和confi ...
- Python开发者最常犯的10个错误
Python是一门简单易学的编程语言,语法简洁而清晰,并且拥有丰富和强大的类库.与其它大多数程序设计语言使用大括号不一样 ,它使用缩进来定义语句块. 在平时的工作中,Python开发者很容易犯一些小错 ...
- python web -- flask
Flask是一个简洁的 Python_web 框架. 零. virtualenv 虚拟环境配置. $ easy_install pip $ pip install virtualenv $ virtu ...
- 【Flask】 项目结构说明
项目结构 Flask的一大优势就是其极其轻量化.但是也需要注意到,如果我们要用Flask做一个大项目的话,把所有代码写在一个文件里肯定是不合适的.非常难以维护.但是和Django这种框架又不一样,Fl ...
随机推荐
- Openssl 加解密文件
使用openssl 的命令行进行文件的加密与解密过程,主要有两种方式: openssl 指定加密/解密算法加密 openssl 指定公钥/私钥文件加密 openssl 指定加密/解密算法加密 To E ...
- RocketMQ之六:RocketMQ消息存储
一.RocketMQ的消息存储基本介绍 先看一张图: 1.Commit log存储消息实体.顺序写,随机读.2.Message queue存储消息的偏移量.读消息先读message queue,根据偏 ...
- Windows用Eclipse来开发hadoop的WordCount的helloworld
[学习笔记] 2.Win7用Eclipse来开发hadoop的WordCount的helloworld网上下载hadoop-eclipse-plugin-2.7.4.jar,将该jar包拷贝到Ecli ...
- 第三坑:jar包编译版本
这个是之前往was上发应用的时候踩的一个坑,当时我们知道was的jdk版本是1.6,然后我们是用1.7的jdk,编译版本选的是1.6,然后放上去不对,我们以为是编译的问题,然后又下载了1.6的jdk, ...
- 使用网关zuul过滤器登录鉴权
使用网关zuul过滤器登录鉴权 1.新建一个filter包 filte有很多种 pre.post. 2.新建一个类LoginFilter,实现ZuulFilter,重写 ...
- sql根据时间戳按年月日分组统计
sql根据时间戳按年月日分组统计,用于按日期分类: create_time为时间格式(字段名create_time 根据自己表字段修改,数据库中存为201610071202) SELECT DATE_ ...
- PCA降维笔记
PCA降维笔记 一个非监督的机器学习算法 主要用于数据的降维 通过降维, 可以发现更便 于人类理解的特征 其他应用:可视化:去噪 PCA(Principal Component Analysis)是一 ...
- C++中的swap(交换函数)
交换两个变量的值很简单. 比如 int a = 1; b = 2; 交换a b的值 这个很简单 很容易想到的是找个中间变量比如 int temp = a; a = b; b = temp; 不需要 ...
- GPIO 输出—使用固件库点亮 LED
编程要点 1. 使能 GPIO 端口时钟: 2. 初始化 GPIO 目标引脚为推挽输出模式: 3. 编写简单测试程序,控制 GPIO 引脚输出高.低电平. LED的电路图 过程: 1.拷贝一个库函 ...
- sql 计算奇数还是偶数
& 运算符来判断奇数还是偶数 sql判断奇数还是偶数 3&1 返回 1 2&1 返回0 0&1 返回 0