如何使用quoted-printable transfer-encoding和utf-8 content-encoding发送电子邮件?

时间:2015-07-30 02:24:44

标签: python email smtp

python的email.mime倾向于使用编码base647bitus-ascii。我想使用quoted-printableutf-8

目前,我的电子邮件看起来像

--===============6135350048414329636==
Content-Type: text/plain
MIME-Version: 1.0
Content-Transfer-Encoding: base64

IyEvYmluL2Jhc2gKCmZvciBpIGluIHs4Mjg4Li44N

或者,在某些情况下,

--===============0756888342500148236==
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

foobar

我希望原始电子邮件更易于人类阅读。我也更喜欢utf-8编码。

2 个答案:

答案 0 :(得分:6)

简短回答

设置内容传输编码

创建将附加到MIMEText对象的MIMEMultipart对象时,首先将content-transfer-encoding设置为值quoted-printable,然后执行set_payload

# first create MIMEText, then set content-transfer-encoding, then set payload
mt = MIMEText(None, _subtype='plain')
mt.replace_header('content-transfer-encoding', 'quoted-printable')
mt.set_payload(u'happy face ☺', 'utf-8')

# create the parent email object and the MIMEMultipart extension to it
email = MIMEMultipart('mixed')
inline = MIMEMultipart('alternative')

# assemble the objects
inline.attach(mt)
email.attach(inline)

设置电子邮件字符集和电子邮件编码

cs = charset.Charset('utf-8')
cs.header_encoding = charset.QP
cs.body_encoding = charset.QP
email.set_charset(cs)

长脚本示例

以下是一个较长的脚本,可为先前的代码段提供更多上下文。

此脚本将发送以UTF-8编码的text/plain部分。为了好玩,它还会附加一个文件。 它生成的原始电子邮件将是人类可读的(文件附件除外)。

from __future__ import print_function

from email.mime.multipart import MIMEMultipart
from email import charset

# create the parent email object
email = MIMEMultipart('mixed')
# set email charset and email encodings
cs_ = charset.Charset('utf-8')
cs_.header_encoding = charset.QP
cs_.body_encoding = charset.QP
email.set_charset(cs_)

# create the 'text/plain' MIMEText
from email.mime.text import MIMEText
# first create MIMEText, then set content-transfer-encoding, then set payload
mt = MIMEText(None, _subtype='plain')
mt.replace_header('content-transfer-encoding', 'quoted-printable')
mt.set_payload(u'happy face ☺', 'utf-8')

# assemble the parts
inline = MIMEMultipart('alternative')
inline.attach(mt)
email.attach(inline)

# for fun, attach a file to the email
import mimetypes
from email.mime.base import MIMEBase
from email.encoders import encode_base64
my_file = '/tmp/test.sh'
mimetype, encoding = mimetypes.guess_type(my_file)
mimetype = mimetype or 'application/octet-stream'
mimetype = mimetype.split('/', 1)
attachment = MIMEBase(mimetype[0], mimetype[1])
attachment.set_payload(open(my_file, 'rb').read())
encode_base64(attachment)
attachment.add_header('Content-Disposition', 'attachment', filename=os.path.basename(my_file))
email.attach(attachment)

这会创建一个人类可读的原始电子邮件(base64编码文件附件除外)

--===============5610730199728027971==
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset="utf-8"

happy face ☺

--===============5610730199728027971==--

--===============0985725891393820576==
Content-Type: text/x-sh
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="test.sh"

Zm9vYmFyc2RmYXNkZmtqaGFzZGZrbGhhc2ZrbGpoYXNma2xqaGFzZmtsaGZkYXNmCg==

--===============0985725891393820576==--

(奖金)发送电子邮件

使用smtplib,可以通过电子邮件发送电子邮件。

# set email address headers
email['From'] = 'me@email.com'
email['To'] = 'you@email.com'
email['Subject'] = 'hello'

# send the email
import smtplib
smtp_srv = smtplib.SMTP('localhost')
smtp_srv.set_debuglevel(True)
print(mesg_html, end='\n\n')
print(email.as_string(), end='\n\n')
smtp_srv.sendmail('me@email.com', 'you@email.com', email.as_string())
smtp_srv.quit()

答案 1 :(得分:2)

在尝试更改现有邮件(email.Message对象)的正文并将其编码设置为quoted-printable时,我发现此问题花费了比我预期更多的精力。

import email
#... 'part' is the Message object
content = part.get_payload(decode=True)
#... Modify content
part['Content-Transfer-Encoding'] = '8bit'
part.set_payload(content, 'UTF-8')
del part['Content-Transfer-Encoding']
email.encoders.encode_quopri(part)

现在,为什么要设置然后删除Content-Transfer-Encoding标头?如果没有头,则set_payload调用将设置Content-Transfer-Encoding头并编码数据(到Base64)。否则,set_payload调用将假定调用方已经对数据进行了编码,并且不会(通过编码)更改数据。因此,实际上我设置Content-Transfer-Encoding标头的值并不重要,只是我没有将其留空。

但是为什么我需要删除标题? email.encoders.encode_quopri调用只会添加一个标题,因此该消息将带有多个Content-Transfer-Encoding标题。

因此,仅对没有set_payload头的消息使用encode_quopri然后对Content-Transfer-Encoding使用Content-Transfer-Encoding,将得到带引号的可打印的Base64字符串表示形式,对于具有现有{ {1}}标头将导致带有重复标头的消息。然后使用encode_quopriset_payload可能会导致标题重复,但不会对消息进行编码。因此,添加/删除rigamarole以避免陷入the quopri module