最近接手了一个 py 机器人的开发,发现不论传入的附件路径是变量、字符串、先编码后解码的字符串都解决不了名称乱码。
打开源码一看,是这个逻辑:
def send_smtp_mail(server=None,port=25,psw=None,sender=None,receivers=None,cc=None,bcc=None,subject=None,body=None,attachments=None,ssl='no'):
'''
SMTP发送邮件
server:smtp服务器 port:端口号 psw:登陆密码 sender:发送方 receivers:接收者
cc:抄送 bcc:密抄 subject:标题 body:邮件正文 attachments:附件路径
'''
__logger.debug('smtp Send mail:[' + str(server) + '][' + str(port) + ']')
re = []
try:
msgRoot = MIMEMultipart()
#msgRoot['Subject'] = subject 构造标题
msgRoot['Subject'] = Header(subject, 'utf-8').encode()
msgRoot['Cc'] = "".join(str(cc))
msgRoot['Bcc'] = "".join(str(bcc))
msgRoot['From'] = formataddr(["", sender])
msgRoot['To'] = formataddr(["", receivers])
msgRoot.attach(MIMEText(body, 'plain', 'utf-8'))
if attachments != None:
for attachment in attachments.split(','):
rst= os.path.exists(attachment)
if rst :
excelFile = open(attachment, 'rb').read()
fileName = os.path.basename(os.path.realpath(attachment))
att = MIMEApplication(excelFile)
att.add_header('Content-Disposition', 'attachment', fileName=('gbk', '', fileName))
msgRoot.attach(att)
else:
__logger.debug(u'Attachment path does not exist')
if receivers != None and receivers != '':
re = receivers.split(',')
if cc != None and cc != '':
re = re + str(cc).split(',')
if bcc !=None and bcc != '':
re = re + str(bcc).split(',')
smtp = smtplib.SMTP()
if ssl=='yes':
smtp = smtplib.SMTP_SSL()
smtp.connect(server,port)
psw = encrypt.decrypt(psw)
smtp.login(sender, psw)
smtp.sendmail(sender,re, msgRoot.as_string())
smtp.quit()
except Exception as e:
raise e
finally:
__logger.echo_msg(u"end execute[sendMail]")
发现这里对附件的处理只是获取真正的附件名,并传入 Content-Disposition 中。在 segmentfault 查到,要给 fileName 进行两次 utf-8 编码、然后用 email.header 库的 make_header() 函数处理一次附件名、才传给 Content-Disposition 中。 修改之后的源码可以正常识别中文名字的附件了,贴一下修改后的源代码:
def send_smtp_mail1(server=None,port=25,psw=None,sender=None,receivers=None,cc=None,bcc=None,subject=None,body=None,attachments=None,ssl='no'):
'''
SMTP发送邮件
server:smtp服务器 port:端口号 psw:登陆密码 sender:发送方 receivers:接收者
cc:抄送 bcc:密抄 subject:标题 body:邮件正文 attachments:附件路径
'''
__logger.debug('smtp Send mail:[' + str(server) + '][' + str(port) + ']')
re = []
try:
msgRoot = MIMEMultipart()
#msgRoot['Subject'] = subject 构造标题
msgRoot['Subject'] = Header(subject, 'utf-8').encode()
msgRoot['Cc'] = "".join(str(cc))
msgRoot['Bcc'] = "".join(str(bcc))
msgRoot['From'] = formataddr(["", sender])
msgRoot['To'] = formataddr(["", receivers])
msgRoot.attach(MIMEText(body, 'plain', 'utf-8'))
if attachments != None:
for attachment in attachments.split(','):
rst= os.path.exists(attachment)
if rst :
excelFile = open(attachment, 'rb').read()
fileName = os.path.basename(os.path.realpath(attachment))
att = MIMEApplication(excelFile)
att.add_header('Content-Disposition', 'attachment', fileName = "%s" % make_header([(fileName, 'UTF-8')]).encode('UTF-8') )
msgRoot.attach(att)
else:
__logger.debug(u'Attachment path does not exist')
if receivers != None and receivers != '':
re = receivers.split(',')
if cc != None and cc != '':
re = re + str(cc).split(',')
if bcc !=None and bcc != '':
re = re + str(bcc).split(',')
smtp = smtplib.SMTP()
if ssl=='yes':
smtp = smtplib.SMTP_SSL()
smtp.connect(server,port)
psw = encrypt.decrypt(psw)
smtp.login(sender, psw)
smtp.sendmail(sender,re, msgRoot.as_string())
smtp.quit()
except Exception as e:
raise e
finally:
__logger.echo_msg(u"end execute[sendMail]")
所以不要迷信什么产品的内置函数,,业务开发真的有很多细节要考虑周全啊。原始答案在: python3发邮件,附件名称为中文时出错 - SegmentFault 思否
(完)