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 ...
随机推荐
- 表单绑定 v-model
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- Jmeter 跨线程组传递参数 之两种方法(转)
终于搞定了Jmeter跨线程组之间传递参数,这样就不用每次发送请求B之前,都需要同时发送一下登录接口(因为同一个线程组下的请求是同时发送的),只需要发送一次登录请求,请求B直接用登录请求的参数即可,直 ...
- Win10 鼠标右键新建菜单添加自定义文件
1. 引言 在鼠标右键(右单机)新建菜单中添加自定义文件,例如:写字板,markdown等. 效果图: 2. 操作步骤(以Win10为例) 1. win+R输入regedit进入注册表 2. 这里以添 ...
- gdb 常用命令总结(精优)
格式说明: [xxx]:可选参数,即可以指定可以不指定,实际输入的内容是 xxx <xxx>:占位参数,即必须指定的参数,实际输入的内容是 xxx gdb 常用命令: gdb [file] ...
- jquery 广告轮播图
轮播图 /*轮播图基本功能: * 1图片切换 * 1.1图片在中间显示 * 1.2图片淡入淡出 * 2左右各有一个按钮 * 2.1点击左按钮,图片切换上一张 * 2.2点击右按钮,图片切换下一张 * ...
- Windows下命令行Git无法显示中文问题解决方案
Windows下Git设置编码正常显示中文: 在 CMD 下设置环境变量 set LESSCHARSET=utf-8 在 PowerShell 下设置环境变量 $env:LESSCHARSET='ut ...
- 1.ASP.NET Core Docker学习-Docker介绍与目录
Docker的优点: 1节约时间,快速部署和启动 2节约成本 3标准化应用发布 4方便做持续集成 5可以用Docker做为集群中的轻量主机或节点 6方便构建基于SOA或者微服务架构 的系统 学习目录: ...
- ActiveMQ的静态网络配置
static networkConnector是用于创建一个静态的配置对于网络中的多个Broker做集群,这种协议用于复合url,一个复合url包括多个url地址. <networkConnec ...
- idea jetty:run 启动
1.首先pom 文件 <!-- jetty插件 --> <plugin> <groupId>org.mortbay.jetty</groupId> ...
- linux安装tmux分屏插件
linuxtmux分屏 一.安装tmux 二.基本使用 三.鼠标操作 一.安装tmux yum install -y tmux TMUX2版本以下 二.基本使用 使用tmux一般使用命令和快捷键来操作 ...