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
相关产品推荐
相关产品推荐

