procmail处理后的邮件正文编码
我在SMTP服务器的.procmailrc文件里有这么一行:
BODY=`formail -I ""`
后来我把这个内容输出到一个本地文件里:
echo "$BODY" >> $HOME/$FILENAME; \
我也试过用printf(但效果是一样的):
printf "$BODY" >> $HOME/$FILENAME; \
当我读取这个文件时,发现编码发生了变化。结果是这样的:
Administrator System=C3=B3w
而它应该是(用波兰语):
Administrator Systemów
我该如何在.procmailrc里直接解码/编码这个内容,或者在后面用(bash/python)来获取正确的字符串呢?
我在.procmailrc
里的另一行工作正常,但需要额外用perl编码:
SUBJECT=`formail -xSubject: | tr -d '\n' | sed -e 's/^ //' | /usr/bin/perl -MEncode -ne 'print encode ("utf8",decode ("MIME-Header",$_ )) '`
主题(SUBJECT)包含UTF8字符,一切看起来都没问题。也许可以用类似的方法处理邮件的内容呢?
好的。最后我把一切都搞定了。以下是我做的:
首先是.procmailrc文件:
VERBOSE=yes
LOGFILE=$HOME/procmail.log
:0f
* ^From.*(some_address@somedomain.com)
| $HOME/python_script.py
接下来是python_script.py:
#!/usr/bin/python
from email.parser import Parser
import sys
temp_file = open("/home/(user)/file.txt","w")
temp_file.write("START\n")
if not message.is_multipart():
temp_file.write(message.get_payload(decode=True))
else:
for part in message.get_payload():
if part.get_content_type() == 'text/plain':
temp_file.write(part.get_payload(decode=True))
temp_file.close()
最难调试的部分是.procmailrc的设置,我得测试很多选项,比如:0, :0f, :0fbW等等,最后找到最合适的。
下一个麻烦的步骤是$BODY部分直接在.procmailrc里解码。不过我找到了解决办法,把所有内容都移到Python脚本里,就像tripleee建议的那样。
2 个回答
我觉得可能是你的 echo
没有正确返回 Unicode 字符,导致写入文件时出现问题。这里有两个可能的解决办法,可以帮助你:
第一种方法是使用转义字符来输出:
echo -e "$BODY" >> $HOME/$FILENAME; \
或者,你可以使用 iconv
或类似的工具将你的文件编码为 utf-8,前提是你的 Linux 系统上安装了 iconv。
iconv -t UTF-8 original.txt > encoded_result.txt
其实并没有改变,但你把一些头信息给删掉了,导致正确的 Content-Type:
头信息不见了(你还应该保留 Mime-Version:
和其他标准的 Content-*
头信息)。
你可以通过查看邮件客户端中的消息源,发现 Procmail 或 Bash 实际上并没有改变任何东西。你收到的文本实际上是 Administrator System=C3=B3w
,但是 MIME 头信息告诉你的邮件客户端这是 Content-Transfer-Encoding: quoted-printable
和 Content-type: text/plain; charset="utf-8"
,所以它知道怎么正确解码和显示这些内容。
如果你只想要内容本身,你需要自己解码,但为了做到这一点,你需要从 MIME 头信息中获取这些信息,所以在处理消息之前不应该删掉这些头信息(如果真的要删的话)。也许可以这样做:
from email.parser import Parser
import sys
message = Parser().parse(sys.stdin)
if message['content-type'].lower().startswith('text/'):
print(message.get_payload(decode=True))
else:
raise DieScreamingInAnguish('aaaargh!') # pseudo-pseudocode
这个方法非常简单,因为它假设(就像你现在的那个更糟糕的解决方案)消息只包含一个文本部分。要扩展到多部分消息并不难,但具体怎么做取决于你期望收到什么样的多部分内容,以及你想对这些内容做什么。
就像在 你之前的问题 中提到的,我建议你把更多的,或者全部的邮件处理工作放到 Python 中去做,如果你本来就打算使用它的话。Procmail 并没有明确支持 MIME,所以你需要在 Procmail 中重新实现所有这些功能,这既不简单也不太有意义。