无法在Web浏览器中邮件正文显示日文(UTF-8)字符

4 投票
1 回答
1630 浏览
提问于 2025-04-18 05:56

我正在从两个不同的.txt文件中读取文本,并把它们合并在一起。然后通过使用webbrowser把这些内容放到电子邮件的正文里。

其中一个文本文件是英文字符(ascii),另一个是日文(UTF-8)。如果我把文本写入一个文本文件,它显示得很好。但是如果我用webbrowser把文本插入到电子邮件正文中,日文就显示成问号了。

我尝试在多台机器上运行这个脚本,这些机器的默认邮件客户端不同。起初我以为这可能是问题所在,但似乎并不是。Thunderbird和Mail(MacOSX)都显示问号。

Hello. Today is 2014-05-09

????????????????2014-05-09????

我查看了StackOverflow上类似的问题,但没有找到解决办法。

有没有办法让日文(UTF-8)在用webbrowser创建的电子邮件正文中正常显示?我可以使用email功能,但要求是脚本需要打开默认的邮件客户端并插入所有信息。

下面是我使用的代码和文本文件。我简化了内容,以便专注于这个问题。

email-template.txt

Hello. Today is {{date}}

email-template-jp.txt

こんにちは。今日は {{date}} です。

Python脚本

#
# -*- coding: utf-8 -*-
#

import sys
import re
import os
import glob
import webbrowser
import codecs,sys

sys.stdout = codecs.getwriter('utf8')(sys.stdout)

# vars
date_range = sys.argv[1:][0]

email_template_en   = "email-template.txt"
email_template_jp   = "email-template-jp.txt"   
email_to_send       = "email-to-send.txt"       # finished email is saved here

# Default values for the composed email that will be opened
mail_list           = "test@test.com"
cc_list             = "test1@test.com, test2@test.com"
subject             = "Email Subject"

# Open email templates and insert the date from the parameters sent in
try:
    f_en = open(email_template_en, "r")
    f_jp = codecs.open(email_template_jp, "r", "UTF-8")
    try:
        email_content_en = f_en.read()
        email_content_jp = f_jp.read()

        email_en = re.sub(r'{{date}}', date_range, email_content_en) 
        email_jp = re.sub(r'{{date}}', date_range, email_content_jp).encode("UTF-8") 
        # this throws an error
        # UnicodeDecodeError: 'ascii' codec can't decode byte 0xe3 in position 26: ordinal not in range(128)
        # email_en_jp = (email_en + email_jp).encode("UTF-8") 
        email_en_jp = (email_en + email_jp)
    finally:
        f_en.close()
        f_jp.close()
    pass
except Exception, e:
    raise e

# Open the default mail client and fill in all the information
try:
    f = open(email_to_send, "w")
    try:
        f.write(email_en_jp)
        # Does not send Japanese text to the mail client. But will write to the .txt file fine. Unsure why.
        webbrowser.open("mailto:%s?subject=%s&cc=%s&body=%s" %(mail_list, subject, cc_list, email_en_jp), new=1) # open mail client with prefilled info
    finally:
        f.close()
    pass
except Exception, e:
    raise e

编辑:忘了说我使用的是Python 2.7.1

1 个回答

3

编辑 2: 最终找到一个可行的解决方案。

把你的 webbrowser 调用替换成这个。

import subprocess
[... other code ...]
arg = "mailto:%s?subject=%s&cc=%s&body=%s" % (mail_list, subject, cc_list, email_en_jp)
subprocess.call(["open", arg])

这会在 MacOS 上打开你默认的邮件客户端。对于其他操作系统,请在 subprocess 这一行把 "open" 替换成相应的可执行文件。


编辑: 我进一步研究了一下,Mark 上面的评论让我去阅读了 RFC (2368),这是关于 mailto URL 方案的。

特殊的 hname "body" 表示相关的 hvalue 是消息的
正文。 "body" hname 应该包含消息的
第一个 text/plain 正文部分的内容。mailto URL 主要是为了生成短文本消息,这些消息实际上是自动处理的内容(比如订阅邮件列表的消息),而不是一般的 MIME 正文。

再往下看:

在 mailto URLs 中,禁止使用 8 位字符。MIME 编码的单词(如 [RFC2047] 中定义的)在头部值中是允许的,但不适用于 "body" hname 的任何部分。

所以根据 RFC 的规定,这似乎是不可能的,尽管这让我怀疑 naota 提供的 JSFiddle 中的 JavaScript 解决方案为什么能工作。


我把之前的回答保留在下面,尽管它并不有效。


我在使用 Python 2.7.x 时遇到过同样的问题好几次,每次都有不同的解决方案能成功。

所以这里有几个建议,可能有效也可能无效,因为我没有测试过。

a) 强制使用 Unicode 字符串:

webbrowser.open(u"mailto:%s?subject=%s&cc=%s&body=%s" % (mail_list, subject, cc_list, email_en_jp), new=1)

注意在开头的 ( 后面和 " 前面有个小 u。

b) 强制正则表达式使用 Unicode:

email_jp = re.sub(ur'{{date}}', date_range, email_content_jp).encode("UTF-8") 
# or maybe
email_jp = re.sub(ur'{{date}}', date_range, email_content_jp)

c) 关于正则表达式的另一个想法,尝试先用 re.UNICODE 标志编译它,然后再应用。

pattern = re.compile(ur'{{date}}', re.UNICODE)

d) 虽然不直接相关,但我注意到你是通过普通的 open 方法写入组合文本。这里也尝试使用 codecs.open

f = codecs.open(email_to_send, "w", "UTF-8")

希望这能帮到你。

撰写回答