二进制文件邮件附件问题

8 投票
3 回答
17767 浏览
提问于 2025-04-15 22:31

我在使用Python 3.1.2的时候,遇到了发送二进制附件文件(比如jpeg、pdf等)的问题——而MIMEText类型的附件发送得很好。下面是相关的代码...

for file in self.attachments:
   part = MIMEBase('application', "octet-stream")
   part.set_payload(open(file,"rb").read())
   encoders.encode_base64(part)
   part.add_header('Content-Disposition', 'attachment; filename="%s"' % file)
   msg.attach(part)   # msg is an instance of MIMEMultipart()

server = smtplib.SMTP(host, port)
server.login(username, password)
server.sendmail(from_addr, all_recipients, msg.as_string())

不过,在调用栈的深处(见下面的错误追踪信息),看起来msg.as_string()接收到了一个附件,这导致它生成了一个'bytes'类型的负载,而不是字符串。

有没有人知道可能是什么原因导致这个问题的?任何帮助都非常感谢。

Alan


builtins.TypeError: string payload expected: <class 'bytes'>
File "c:\Dev\CommonPY\Scripts\email_send.py", line 147, in send
  server.sendmail(self.from_addr, all_recipients, msg.as_string())
File "c:\Program Files\Python31\Lib\email\message.py", line 136, in as_string
  g.flatten(self, unixfrom=unixfrom)
File "c:\Program Files\Python31\Lib\email\generator.py", line 76, in flatten
  self._write(msg)
File "c:\Program Files\Python31\Lib\email\generator.py", line 101, in _write
  self._dispatch(msg)
File "c:\Program Files\Python31\Lib\email\generator.py", line 127, in _dispatch
  meth(msg)
File "c:\Program Files\Python31\Lib\email\generator.py", line 181, in _handle_multipart
  g.flatten(part, unixfrom=False)
File "c:\Program Files\Python31\Lib\email\generator.py", line 76, in flatten
  self._write(msg)
File "c:\Program Files\Python31\Lib\email\generator.py", line 101, in _write
  self._dispatch(msg)
File "c:\Program Files\Python31\Lib\email\generator.py", line 127, in _dispatch
  meth(msg)
File "c:\Program Files\Python31\Lib\email\generator.py", line 155, in _handle_text
  raise TypeError('string payload expected: %s' % type(payload))

3 个回答

3
for file in self.attachments:
   fp = open(file,"rb")    
   part = MIMEApplication( fp.read() )    
   fp.close()    
   encoders.encode_base64(part)

   # the miracle
   part.set_payload( part.get_payload().decode('ASCII') )

   part.add_header('Content-Disposition', 'attachment; filename="%s"' % file)    
   msg.attach(part)   

当然可以!请把你想要翻译的内容发给我,我会帮你用简单易懂的语言解释清楚。

6

这个解决方案来自于这个StackOverflow的回答

from base64 import encodebytes
for file in self.attachments:
    fp = open(file, 'rb')
    part = MIMEBase('application', "octet-stream")
    part.set_payload(encodebytes(fp.read()).decode())
    fp.close()
    part.add_header('Content-Transfer-Encoding', 'base64')
    part.add_header('Content-Disposition', 'attachment; filename="%s"' % file)
    msg.attach(part)   # msg is an instance of MIMEMultipart()

server = smtplib.SMTP(host, port)
server.login(username, password)
server.sendmail(from_addr, all_recipients, msg.as_string())
3

好的,经过很多的挫折和在网上的搜索,我发现这个问题是一个已知的 bug,出现在 Python 3.x 的 encoders.py 文件中的 encode_base64 函数,应该是这样的...

def encode_base64(msg):
    """Encode the message's payload in Base64.

    Also, add an appropriate Content-Transfer-Encoding header.
    """
    orig = msg.get_payload()
    encdata = _bencode(orig)

    # new line inserted to ensure all bytes characters are converted to ASCII
    encdata = str(encdata, "ASCII")

    msg.set_payload(encdata)
    msg['Content-Transfer-Encoding'] = 'base64'

这个 bug 被记录为问题 #4768,并在 2010 年 5 月 10 日被提升为严重问题。希望在下一个版本(3.1.3?)中能修复这个问题。

祝好,Alan

撰写回答