python2.7 解决email foxmail for mac 收到附件无后缀未命名文件,无发件人,漏掉邮件内容问题

本文主要介绍了在使用Python2.7处理邮件时遇到的Foxmail for Mac显示问题,包括附件无后缀、发件人和邮件内容丢失。通过分析源码和调整邮件构造方式,成功解决了这些问题。提供了一段修复后的邮件发送代码。

python2.7 解决email中foxmail for mac 收到附件无后缀,无发件人,漏掉邮件内容问题:https://blog.youkuaiyun.com/SHSQLDLL/article/details/86700029

一、附件无后缀的问题

#之前写的发送附件时(在windows的foxmail接收无问题,mac的foxmail的附件大于2M时会出现问题):
file = "test.txt"
message = MIMEMultipart()
att1 = MIMEText(open(file , 'rb').read(), 'base64', 'utf-8')
att1["Content-Type"] = 'application/octet-stream'
att1["Content-Disposition"] = 'attachment; filename="%s"'%file#这里的filename就是附件名称展示
message.attach(att1)

在windows的foxmail和网页版的邮件均可正常接收,展示正确的附件名称.

但是突然一天发送的附件超过2M时, foxmail for mac中接收到到附件就展示成"未命名文件"了......

查看foxmail for mac中的源码(导出邮件.eml用txt打开查看)时,看到filename="=?utf-8?B?5pyq5ZG95ZCN5paH5Lu2?="解码过来就是"未命名文件",应该是发送时格式有问题, 找了n种方法,试了将filename写死(filename="abc.txt")不会出问题, 文件大小为1M多不会出问题...查看email中的message.py文件,发现提供了一个add_header方法来新增, 试用后居然可以了.

暂时未发现问题所在, 请了解的同学回复一下.

#修改后的,在windows/mac的foxmail中均展示正常

def addMessageHeader(message,key,value,**params):
    message.__delitem__(key)#Content-Type,Content-Disposition 等若不删除的话可能会同时存在两个
    message.add_header(key,value,**params)#该方式在foxmail mac/windows 接收均正常

file = "test.txt"#大于3M
message = MIMEMultipart()
att1 = MIMEText(open(file , 'rb').read(), 'base64', 'utf-8')
addMessageHeader(att1 ,"Content-Type","application/octet-stream",name=filename)
addMessageHeader(att1 ,"Content-Disposition","attachment",filename=filename)#使用该方法可避
                                            #免foxmail for mac接受到的文件名展示为"未命名文件
message.attach(att1)

二、收件人,发件人,主题在foxmail for mac中接受为utf解码异常甚至是为空的情况

#之前的写法,在windows的foxmail中总是正常, 在mac的foxmail总是有问题
message = MIMEMultipart()
message['From'] = Header("aaa@qq.com", 'utf-8')
message['To'] =  Header("aaa@qq.com", 'utf-8')
message['Subject'] = Header('邮件测试', 'utf-8')

同上面情况一样,无论是否有附件, foxmail for mac展示from,to,subject均会出现接受内容为空的问题,解决方案如上

#修改后的,在windows/mac的foxmail中均正常
#subject = "测试邮件发送接受"#带中文的最好使用下面的方式,前面加上u, 不然会有些小问题,在                         
                           #foxmail windows版本中刚收到时标题是乱码, 邮件收完整后就不会是乱码了
subject = u"测试邮件发送接受"#注意中文最好使用unicode

def addMessageHeader(message,key,value,**params):
    message.__delitem__(key)#Content-Type,Content-Disposition 等若不删除的话可能会同时存在两个
    message.add_header(key,value,**params)#该方式在foxmail mac/windows 接收均正常

addMessageHeader(message,"subject",subject)#如果subject带中文, 在传过来的时候最好是unicode格
                                           #式, 不然也没啥大问题,就是会在foxmail windows版本
                                           #中刚收到时标题是乱码, 邮件收完整后就不会是乱码了
addMessageHeader(message,"From","abc@qq.com")
addMessageHeader(message,"To","abc@qq.com")

三、foxmail for mac 漏掉邮件内容的情况

1.两条plain格式

#之前写的有问题的代码,在windows/mac的foxmail中均展示有遗漏, 只展示最后一条的内容了
message = MIMEMultipart()
text1 = "测试中文内容plain"
text2= "测试html格式"
message.attach(MIMEText(text1, 'plain', 'utf-8'))
message.attach(MIMEText(text2, 'plain', 'utf-8'))

#邮件格式如下:
#注意text/plain格式的foxmail windows/mac中都只会展示相同boundary(1783340315)中的最后一个
#This is a multi-part message in MIME format.
#--===============1783340315==
#Content-Type: text/plain; charset="utf-8"
#MIME-Version: 1.0
#Content-Transfer-Encoding: base64
#
#5rWL6K+V5Lit5paH
#
#--===============1783340315==
#Content-Type: text/plain; charset="utf-8"
#MIME-Version: 1.0
#Content-Transfer-Encoding: base64
#
#dGVzdCBzdHI=
#
#--===============1783340315==--

2.两条html格式

#之前写的有问题的代码
message = MIMEMultipart()
text1 = "<p>测试中文内容plain</p>"
text2= "<p>测试html格式</p>"
message.attach(MIMEText(text1 , 'html', 'utf-8'))
message.attach(MIMEText(text2 , 'html', 'utf-8'))

#在foxmail windows中展示正确;
#在foxmail for mac 中只展示相同boundary(0634571778)中的最后一条
#--===============0634571778==
#Content-Type: text/html; charset="utf-8"
#MIME-Version: 1.0
#Content-Transfer-Encoding: base64
#
#PHA+5rWL6K+V5Lit5paHPC9wPg==
#
#--===============0634571778==
#Content-Type: text/html; charset="utf-8"
#MIME-Version: 1.0
#Content-Transfer-Encoding: base64
#
#PHA+dGVzdCBzdHI8L3A+
#
#--===============0634571778==--

从上可分析出, 一个MIMEText(text , 'html', 'utf-8')会产生一条boundary, attach到同一个MIMEMultipart()时, plain或html是共用一个boundary的,这样不符合MIME标准, 所以为解决这样的问题, 可以把plain和html内容放在一起,整合在同一个html中。

四、附送可用的发邮件的代码

#coding=utf-8
__author__ = 'cemy'
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# from email.header import Header
from email.mime.image import MIMEImage
from email.utils import formatdate
import smtplib
import random,string



sender = {"name":"autoTest",
          "password":"xxx",
          "email":"abc@qq.com",
          "server":"smtp.exmail.qq.com"}
receivers = ["abc@qq.com"]
cc = []
subject = u"测试邮件发送接受"#注意中文最好使用unicode



def addMessageHeader(self,message,key,value,**params):
    message.__delitem__(key)#Content-Type,Content-Disposition 等删除的话会同时出现两个
    message.add_header(key,value,**params)#该方式在foxmail mac/windows 接收均正常

def formContent(content):
    #image = {filename:filepath,filename2:filepath2,...}
    #file = {cid:filepath,cid1:filepath1,...}
    body,image,file = "",{},{}
    for i in range(len(content)):#按顺序组织邮件内容
        key = content[i][0]
        value = content[i][1]
        if key == "plain":#(plain,"")
            body += """<p>%s</p>"""%(value)
        elif key =="html":#(html,"")
            body += value
        elif key == "files":#(files,{filename:filepath,...})
            file = dict(file.items() + value.items())
        elif key == "imgs":#(imgs,[file1,file2...])
            for i in range(len(value)):
                cid = "image_" + "".join(random.sample(string.digits+string.letters,20))
                body += """<img src="cid:%s""><br>"""%(cid)
                image[cid] = value[i]#value[i]是图片文件名(全路径)
    return body,image,file

def addBody(message,body,images = None):
    related = MIMEMultipart("related")#若要展示图片要这么使用, 不然会展示错误
    alternative = MIMEMultipart("alternative")
    message.attach(related)
    related.attach(alternative)
    alternative.attach(MIMEText(body, 'html', 'utf-8'))#保证文本内容只有一条MIMEText
    for cid in images:
        content = MIMEImage(open(images[cid], 'rb').read())
        content.add_header('Content-ID', cid)
        related.attach(content)

def addFile(message,filename,filePath):
    content = MIMEText(open(filePath, 'rb').read(), 'base64', 'utf-8')
    #message["Content-Disposition"] = 'attachment; filename="test.txt"'#可能会导致foxmail for mac 接受到的文件名异常
    addMessageHeader(content,"Content-Type","application/octet-stream",name=filename)
    addMessageHeader(content,"Content-Disposition","attachment",filename=filename)#使用该方法可避免foxmail for mac接受到的文件名展示为"未命名文件"
    message.attach(content)

def makeContent(message,content):
    body,image,file = formContent(content)#文本/图片/附件分成这3大类,将文本和图片存放位置的html的文本均组织在一起
                                          #foxmail for mac中相同的boundary会只接受最后一条boundary的内容,会导致邮件接受不全
                                          #MIMEText("abc", 'plain', 'utf-8')这里会生成一条boundary,如果有多条这样的文本的内容attach到同一个MIMEMultipart的话, 就会出现相同的boundary
    addBody(message,body,image)
    for filename in file:
        self.addFile(message,filename,file[filename])

def makeMessage(content):
    #content=(("subject",xx),("files"),("html"),("imgs"),("files"),("html"),("imgs"))
    message = MIMEMultipart()
    makeContent(message,content)
    #添加header时:message['To'] =  Header(",".join(receivers),'utf-8')该方式会使foxmail mac 收到会解码错误
    #改用message.add_header(key,value,**params)方式
    addMessageHeader(message,"subject",subject)#如果subject带中文, 在传过来的时候最好是unicode格式, 不然也没啥大问题,就是会在foxmail windows版本中刚收到时标题是乱码, 邮件收完整后就不会是乱码了
    addMessageHeader(message,"From",sender["email"])
    addMessageHeader(message,"To",",".join(receivers))
    addMessageHeader(message,"Date",formatdate())
    if cc:
        addMessageHeader(message,"CC",",".join(cc))
    message.preamble = 'This is a multi-part message in MIME format.'#MIME规范中会有这一句,不加上也没事
    # print message.as_string()#调试时使用, 打印所发送邮件的源码格式
    return message

def send(message):
    try:
        # smtpObj = smtplib.SMTP(sender["server"],25)#大部分云服务器是默认关闭25端口的,建议采用ssl端口
        smtpObj = smtplib.SMTP_SSL(sender["server"],465)#ssl端口

        smtpObj.login(sender["email"],sender["password"])
        smtpObj.sendmail(sender["email"], receivers + cc, message.as_string())
        print "邮件发送成功"
    except smtplib.SMTPException,e:
        print "发送邮件失败,%s"%e.message

html = """
        <p>Python 邮件发送测试...</p>
        <p><a href="http://www.runoob.com">这是一个链接</a></p>
        """
files = {"test":"test.html","test1":"test1.html"}
imgs = ["aaa.jpg"]

message = makeMessage((("plain","begin"),
                       ("imgs",imgs),
                       ("html",html),
                       ("imgs",imgs),
                       ("files",files),
                       ("plain",u"end"),
                       ("plain",u"更多详情请见附件!"),
                       ("plain",u"(本邮件是程序自动下发的,请勿回复!)")))
send(message)

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值