Python中的Unicode错误

0 投票
4 回答
4608 浏览
提问于 2025-04-16 23:28

在下面的代码中,我在 mailServer.sendmail(gmailUser, m.to_addr, msg.as_string()) 这一行遇到了一个错误。

 2011-08-12 17:33:02,542 ERROR  send exception


  Traceback (most recent call last):
    File "sendmail.py", line 33, in bulksend
      mailServer.sendmail(gmailUser, m.to_addr, msg.as_string()).replace(u'\xa0', '')
    File "/usr/lib/python2.4/email/Message.py", line 129, in as_string
      g.flatten(self, unixfrom=unixfrom)
    File "/usr/lib/python2.4/email/Generator.py", line 82, in flatten
      self._write(msg)
    File "/usr/lib/python2.4/email/Generator.py", line 113, in _write
      self._dispatch(msg)
    File "/usr/lib/python2.4/email/Generator.py", line 139, in _dispatch
      meth(msg)
    File "/usr/lib/python2.4/email/Generator.py", line 205, in _handle_multipart
      g.flatten(part, unixfrom=False)
    File "/usr/lib/python2.4/email/Generator.py", line 82, in flatten
      self._write(msg)
    File "/usr/lib/python2.4/email/Generator.py", line 113, in _write
      self._dispatch(msg)
    File "/usr/lib/python2.4/email/Generator.py", line 139, in _dispatch
      meth(msg)
    File "/usr/lib/python2.4/email/Generator.py", line 182, in _handle_text
      self._fp.write(payload)
  UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 173: ordinal not in range(128)
  o

这是 send 方法:

def send(request)
    qs = "......."
    if qs.count():
        smaid = qs[0].id
        gmailUser = 'no-reply@xx.com'
        gmailPassword = 'xx'
        mailServer = smtplib.SMTP('smtp.gmail.com', 587)
        mailServer.ehlo()
        mailServer.starttls()
        mailServer.ehlo()
        mailServer.login(gmailUser, gmailPassword)
        tosend = MailQueue.objects.filter(school = smaid, send = 0)
        for m in tosend:
            msg = MIMEMultipart()
            msg['From'] = gmailUser
            msg['To'] = m.to_addr
            msg["Content-type"] = "text/html"
            sub = m.subject
            sub = sub.replace(u"\u2019"," ")
            msg['Subject'] = sub
            body = m.body
            body = body.replace(u"\u2019"," ")
            msg.attach(MIMEText(body, 'html'))
            mailServer.sendmail(gmailUser, m.to_addr, msg.as_string())
            m.send = 1
            m.save()
        mailServer.close()
    except:
    write_exception("send exception")

4 个回答

0

我觉得当你使用 msg.as_string() 这个方法时,库最终会把内容写入一个像文件一样的对象,这个地方就出现了错误。很可能这个对象只支持ASCII编码,所以不支持Unicode编码。

2

SMTP不支持unicode字符。这意味着在把信息发送给SMTPLIB之前,你需要把邮件的标题和内容转换成字节字符串。

我建议你使用marrow.mailer,而不是自己从头开始写。marrow.mailer会帮你自动处理这些编码问题,包括国际化的域名。

https://github.com/marrow/marrow.mailer

5

首先,你在发送邮件的那行代码之前有一个错误。MIMEText 默认使用 ASCII 字符集,这显然不适合处理 Unicode 字符。你可能会想,如果传入了非 ASCII 的 Unicode,它应该默认使用 utf-8,但实际上并不是这样。(我认为这是一个错误,但在 Python2 中已经太晚无法修复了。)所以你的代码需要告诉 MIMEText 使用哪个字符集:

msg.attach(MIMEText(body, 'html', 'utf-8'))

但是你的错误出现在 MIMEText 之后,这表明可能是你的邮件头中有 Unicode 字符。正如之前提到的,你不能直接把 Unicode 字符发送到 SMTP。不过,解决方法并不是把它编码成 utf-8。因为在邮件头中也不能发送 utf-8(只能在邮件正文中发送)。

要正确地在邮件头中处理 Unicode 字符,应该使用 Header 类(email.header.Header):

msg['Subject'] = Header(sub, header_name='Subject')

是的,这确实很麻烦。而且这看起来有点复杂,因为它会对整个邮件头进行编码,而不仅仅是那些非 ASCII 的部分。我们正在努力让这个过程在 Python3 中变得更简单、更好,但现在还没有做到。

包含 Unicode 的地址更复杂。你需要用 Header 对显示名称进行编码,然后再传递给 formataddr:

disp_name = u'some unicode string'
addr = 'some@address.example.com'
msg['To'] = formataddr((str(Header(disp_name)), addr))

这个地址处理的方法没有文档说明。很多 Python 邮件程序会对整个地址头使用 Header,但这样会产生不符合 RFC 的结果(幸运的是,很多邮件客户端能够正确处理解码)。

所有这些在 Python 3.3 中应该会好很多。

撰写回答