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 ...
随机推荐
- BS
- Stream入门及Stream在JVM中的线程表现
继上次学习过Java8中的非常重要的Lambda表达式之后,接下来就要学习另一个也比较重要的知识啦,也就如标题所示:Stream,而它的学习是完全依赖于之前学习的Lambda表达式. 小实验引入: 这 ...
- 通过 Spring Session 实现新一代的 Session 管理
长期以来,session 管理就是企业级 Java 中的一部分,以致于我们潜意识就认为它是已经解决的问题,在最近的记忆中,我们没有看到这个领域有很大的革新. 但是,现代的趋势是微服务以及可水平扩展的原 ...
- Scala调用Kafka的生产者和消费者Demo,以及一些配置参数整理
kafka简介 Kafka是apache开源的一款用Scala编写的消息队列中间件,具有高吞吐量,低延时等特性. Kafka对消息保存时根据Topic进行归类,发送消息者称为Producer,消息接受 ...
- C++:链表(初识链表)
介绍 链表是把若干个对象用指针串联起来,形成一个链状的数据结构,链表在开发中很重要. 1.链表特征:只需要知道一个链表头,就能访问每个节点的对象. 2.链表遍历:通过每个节点指针next来对的下一个节 ...
- 使用google的guova开发高并发下的接口限流
使用google的guova开发高并发下的接口限流 使用google的guova进行限流 1.guova的限流方式,在定时产生定量的令牌,令牌的数量限制了流量 2.增加一个订单接口限流类OrderRa ...
- (四)网格(dataGrid)
一.普通网格 前端index.jsp <%@ page language="java" contentType="text/html; charset=UTF-8& ...
- Java RadixSort
Java RadixSort /** * <html> * <body> * <P> Copyright 1994-2018 JasonInternational ...
- C# Winform 设置窗口打开的特效
https://www.cnblogs.com/mq0036/p/6421946.html using System.Runtime.InteropServices; public class Win ...
- CPU的基本组成
1.CPU是用来运算的(加法运算.乘法运算.逻辑运算(与.或.非)等) 2.运算操作涉及到数据输入(input).处理.数据输出(output).A和B是输入数据,加法运算时处理.C是输出数据. 3. ...