You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReportLab生成PDF发送邮件时遇UTF-8解码错误求助

问题:ReportLab生成PDF并邮件发送时触发UnicodeDecodeError

错误信息

UnicodeDecodeError at /instruction/testreportgen/
'utf-8' codec can't decode byte 0x93 in position 10: invalid start byte

Unicode error hint
The string that could not be encoded/decoded was: 1.3 %���� R

相关代码

调用函数代码

print('Rendering Report and Sending Mail')
r = renderTestPDF()
sendTestPDF(r)

生成PDF代码

def renderTestPDF():
    canvas = Canvas('hello.pdf')
    canvas.drawString(72, 72, "Hello, World")
    content = canvas.getpdfdata()
    return content

发送邮件代码(原错误版本)

def sendtestpdf(report):
    # Variables For The Server
    emailhost = ''
    emailport = ''

    # Variables For The Email
    systemEmail = ''
    password = ''
    recieveremail = ''

    # Configure The Email Message
    message = MIMEMultipart()
    message["Subject"] = 'This is a test for pdf creation and attachment'
    message["From"] = systemEmail
    message["To"] = recieveremail

    html = """
        <h1>Your report is here!</h1>
    """

    # Turn The Message Into A MIME Object
    part1 = MIMEText(html, "html")

    # 错误出在这里
    binary_pdf = open(report, "rb")
    payload = MIMEBase('application', 'octate-stream', Name="Test.pdf")
    payload.set_payload((binary_pdf).read())
    encoders.encode_base64(payload)
    payload.add_header('Content-Decomposition', 'attachment', filename='Test.pdf')

    # Add HTML/plain-text parts to MIMEMultipart message
    message.attach(part1)
    message.attach(payload)

    # Create Secure Connection with Server and Send Email
    context = ssl.create_default_context()
    with smtplib.SMTP_SSL(emailhost, emailport, context=context) as server:
        server.login(systemEmail, password)
        server.sendmail(systemEmail, recieveremail, message.as_string())

问题分析

renderTestPDF()返回的是PDF二进制字节数据(bytes类型),但你在sendtestpdf里把这个字节数据直接传给了open()函数。open()会尝试把bytes当成文件名字符串去解码,而PDF二进制里包含非UTF-8编码的字节(比如错误里的0x93),这就触发了UnicodeDecodeError。

另外原代码还有两处拼写错误:

  • MIME类型写成了octate-stream,正确应为octet-stream
  • 头字段写成了Content-Decomposition,正确应为Content-Disposition

修复方案

不需要用open()读取文件,直接用返回的二进制数据作为附件内容,同时修正拼写错误:

完整修复后的sendtestpdf函数

def sendtestpdf(report):
    # Variables For The Server
    emailhost = ''
    emailport = ''

    # Variables For The Email
    systemEmail = ''
    password = ''
    recieveremail = ''

    # Configure The Email Message
    message = MIMEMultipart()
    message["Subject"] = 'This is a test for pdf creation and attachment'
    message["From"] = systemEmail
    message["To"] = recieveremail

    html = """
        <h1>Your report is here!</h1>
    """

    # Turn The Message Into A MIME Object
    part1 = MIMEText(html, "html")

    # 修复后的附件处理逻辑
    payload = MIMEBase('application', 'octet-stream', Name="Test.pdf")
    payload.set_payload(report)  # 直接传入PDF二进制数据
    encoders.encode_base64(payload)
    payload.add_header('Content-Disposition', 'attachment', filename='Test.pdf')

    # Add HTML/plain-text parts to MIMEMultipart message
    message.attach(part1)
    message.attach(payload)

    # Create Secure Connection with Server and Send Email
    context = ssl.create_default_context()
    with smtplib.SMTP_SSL(emailhost, emailport, context=context) as server:
        server.login(systemEmail, password)
        server.sendmail(systemEmail, recieveremail, message.as_string())

验证说明

renderTestPDF()返回的getpdfdata()已经是完整的PDF二进制内容,直接传给set_payload即可,不需要再通过文件读取一遍。修改后就能避免解码错误,正常发送带PDF附件的邮件。

内容的提问来源于stack exchange,提问作者Ultimatejuss

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 08:21:57