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的更多相关文章

  1. Python遇到ModuleNotFoundError: No module named 'email.mime'; 'email' is not a package问题的处理办法

    写Python的时候我们会遇到如下的错误: Traceback (most recent call last): File "F:/exploitation/codes/python/Jet ...

  2. 新建py文件时取名千万要小心 不要和已有模块重名

    这是因为我新建了一个email.py的文件 后来我将文件名rename成了myemail.py没有看改名提示,结果导致所有的对email的import和调用全部改成了对myemail的import和调 ...

  3. Python 程序员经常犯的 10 个错误

    关于PythonPython是一种解释性.面向对象并具有动态语义的高级程序语言.它内建了高级的数据结构,结合了动态类型和动态绑定的优点,这使得... 关于Python Python是一种解释性.面向对 ...

  4. Python开发最常犯错误总结10种

    不管是在学习还是工作过程中,人都会犯错.虽然Python的语法简单.灵活,但也一样存在一些不小的坑,一不小心,初学者和资深Python程序员都有可能会栽跟头.本文是Toptal网站的程序员梳理的10大 ...

  5. Python程序的常见错误(收集篇)

    关于Python Python是一门解释性的,面向对象的,并具有动态语义的高级编程语言.它高级的内置数据结构,结合其动态类型和动态绑定的特性,使得它在快速应用程序开发(Rapid Applicatio ...

  6. flask 程序结构概括

    以此结构为例,这个小项目是<Flask Web开发:基于python的web应用开发实战>第一部分结束后的代码框架 第一层 有app.tests.migrations三个文件夹和confi ...

  7. Python开发者最常犯的10个错误

    Python是一门简单易学的编程语言,语法简洁而清晰,并且拥有丰富和强大的类库.与其它大多数程序设计语言使用大括号不一样 ,它使用缩进来定义语句块. 在平时的工作中,Python开发者很容易犯一些小错 ...

  8. python web -- flask

    Flask是一个简洁的 Python_web 框架. 零. virtualenv 虚拟环境配置. $ easy_install pip $ pip install virtualenv $ virtu ...

  9. 【Flask】 项目结构说明

    项目结构 Flask的一大优势就是其极其轻量化.但是也需要注意到,如果我们要用Flask做一个大项目的话,把所有代码写在一个文件里肯定是不合适的.非常难以维护.但是和Django这种框架又不一样,Fl ...

随机推荐

  1. 乐字节Java变量与数据类型之一:Java编程规范,关键字与标识符

    大家好,我是乐字节的小乐,这次要给大家带来的是Java变量与数据类型.本文是第一集:Java编程规范,关键字与标识符. 一.编程规范 任何地方的名字都需要见名知意: 代码适当缩进 书写过程成对编程 对 ...

  2. [转帖]Pivotal Greenplum 6.0 新特性介绍

    Pivotal Greenplum 6.0 新特性介绍 https://cloud.tencent.com/developer/news/391063 原来 greenplum 也是基于pg研发的. ...

  3. LeetCode 题目的 Python 实现(持续更新中)

    Python-LeetCode 是一个使用 Python 语言解决 LeetCode 问题的代码库,库有以下几个方面需要注意: 所有题目都是 AC 的: 按照题目顺序,每 50 个放在一个目录下,方便 ...

  4. Python之并行编程笔记

    概述: 非并发: 1 程序由单个步骤序列构成  2 包含独立子任务的程序执行性能低 并发:  1 异步.高效  2 分解子任务.简化流程与逻辑 进程process:1 一个程序的执行实例  2 每个进 ...

  5. 跟我一起学编程—《Scratch编程》第24课:幸运大转盘

    同学你好,欢迎来到<跟我一起学编程>,我是包老师.这是<Scratch3.0编程>课程的第24课,我这节课教你做一个抽奖游戏:幸运大转盘. 学习目标: 1. 能够熟练使用造型工 ...

  6. springboot + quartz

    在这里我单独整理对定时任务的使用.之前觉得用@Scheduled这个注解就可以解决,后来发现,定时任务比较多时,且时间集中在某个时间段,或者执行的时间间隔比较短时,多个任务执行就会依次执行,这就导致任 ...

  7. oracle查询十分钟之前的数据

    select * from TABLE as of timestamp sysdate - 10/1440 t WHERE ColName='1111'; TABLE:表名 WHERE:查询子句 sy ...

  8. 菜鸡之NetCore 使用EF操作数据库 Oracle & Sqlserver (一)

    摘要: 该篇文章主要记录netCore EFCore 如何操作Oracle和SqlServer 数据库,采用Codefirst方式创建数据库以及表. 一, 项目建立 项目采用DDD领域驱动设计模式[学 ...

  9. 利用Supervisor 管理自己部署的应用程序

    首先,在centos7下安装supervisor yum install python-setuptools easy_install supervisor 然后新建配置文件 #新建superviso ...

  10. [转载]详解网络传输中的三张表,MAC地址表、ARP缓存表以及路由表

    [转载]详解网络传输中的三张表,MAC地址表.ARP缓存表以及路由表 虽然学过了计算机网络,但是这部分还是有点乱.正好在网上看到了一篇文章,讲的很透彻,转载过来康康. 本文出自 "邓奇的Bl ...