背景
从不同渠道收到的文档,要发统一邮箱归档。
需求:
1、必须一个文档单独发一封邮件,不接受合并。
2、没有自己的邮件服务器。
问题:
发现用QQ邮箱smtp发送文档时,短时间发送10封以上,会被限流。
限流后10分钟左右可再发。
解决方式:
每发一封,sleep 5s,再发,则不会触发限流
脚本代码
发送脚本
发送成功后,为了便于管理,会删除已经发送的文件
from email.mime.multipart import MIMEMultipart
from src.MailAssembler import MailAssembler
from src.MailSender import MailSender
import os
import time
from_name = "xx"
from_mail = "xx@qq.com"
to_mail = ["xx@qq.com"]
cc_mail = []
rootdir = "/mnt/e/Desktop/xx/"
def getFileName(path):
list = path.split("/")
filename = list[len(list) - 1]
return filename
list = os.listdir(rootdir)
smtpserver = "smtp.qq.com"
smtpport = 465
password = "xxx" # 授权码,需要自己在设置里开通并短信获取
list = os.listdir(rootdir)
for i in range(0,len(list)):
path = os.path.join(rootdir,list[i])
if os.path.isfile(path):
filename=getFileName(path)
subject = filename
msg = MIMEMultipart()
assembler = MailAssembler()
sender = MailSender(smtpserver,smtpport,password,from_mail,to_mail,cc_mail)
assembler.attachAttributes(msg,subject,from_name,from_mail,to_mail,cc_mail)
assembler.attachAttachment(msg,path)
if sender.sendMail(msg,filename) is True :
try:
os.remove(path)
time.sleep(5)
except Exception as e:
print ("发送成功删除失败",filename)
辅助函数:
MailAssembler.py
from email.header import Header
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email import encoders
from email.header import make_header
class MailAssembler:
def attachAttributes(self,msg,subject,from_name,from_mail,to_mail,cc_mail=None):
msg["Subject"] = Header(subject, "utf-8")
msg["From"] = Header(from_name + " <" + from_mail + ">", "utf-8")
msg["To"] = Header(",".join(to_mail), "utf-8")
msg["Cc"] = Header(",".join(cc_mail), "utf-8")
def attachBody(self,msg,body,type,imgfile=None):
msgtext = MIMEText(body, type, "utf-8")
msg.attach(msgtext)
if imgfile != None:
try:
file = open(imgfile, "rb")
img = MIMEImage(file.read())
img.add_header("Content-ID", "<image1>")
msg.attach(img)
except(Exception) as err:
print(str(err))
finally:
if file in locals():
file.close()
def attachAttachment(self,msg,attfile):
att = MIMEBase("application", "octet-stream")
try:
file = open(attfile, "rb")
att.set_payload(file.read())
encoders.encode_base64(att)
except(Exception) as err:
print(str(err))
finally:
if file in locals():
file.close()
if "\\" in attfile:
list = attfile.split("\\")
filename = list[len(list) - 1]
if "/" in attfile:
list = attfile.split("/")
filename = list[len(list) - 1]
else:
filename = attfile
att.add_header("Content-Disposition", "attachment; filename=\"%s\"" % make_header([(filename, 'UTF-8')]).encode('UTF-8'))
msg.attach(att)
MailSender.py
import smtplib
class MailSender:
def __init__(self,smtpserver,smtpport,password,from_mail,to_mail,cc_mail=None):
self.smtpserver = smtpserver
self.smtpport = smtpport
self.password = password
self.from_mail = from_mail
self.to_mail = to_mail
self.cc_mail = cc_mail
def sendMail(self,msg,name):
try:
smtp = smtplib.SMTP_SSL(self.smtpserver, self.smtpport)
smtp.login(self.from_mail, self.password)
if self.cc_mail == None:
smtp.sendmail(self.from_mail, self.to_mail, msg.as_string())
else:
smtp.sendmail(self.from_mail, self.to_mail+self.cc_mail, msg.as_string())
print("successful %s" % name)
return True
except(smtplib.SMTPRecipientsRefused):
print("Recipient refused %s" % name)
return False
except(smtplib.SMTPAuthenticationError):
print("Auth error %s" % name)
return False
except(smtplib.SMTPSenderRefused):
print("Sender refused %s name")
return False
except(smtplib.SMTPException) as e:
print(name,e.message)
return False
finally:
smtp.quit()