我编写了一个脚本,用于fetchmail
从帐户获取邮件并将消息通过管道传送到procmail
它以应用过滤器并保存附件。我对消息主题使用了过滤器,但源主题中有西里尔字母,因此当fetchmail
将消息通过管道传输到procmail
最终主题时,会以 UTF-8 加密开始,然后只是乱码。
Procmail
脚本看起来像这样:
:0fHw
*^Content-Type:*text/plain; *charset="?(iso-8859-1|US-ASCII|UNKNOWN-8BIT)"?
| formail -i "Content-Type: text/plain; charset=windows-1251"
:0
*^content-Type:
{
:0c
$HOME/fetchmail/backup
:0f
*^Subject:.*ASVA
| uudeview -i +a +o -p $HOME/fetchmail/attachments -
}
这些脚本在拉丁主题上完美运行,但由于西里尔主题,我的过滤器看不到我输入的关键字。如何将主题转换为以正确的西里尔字母和拉丁字母显示?我安装了语言包,本地设置为 ru_RU:UTF-8,当我用西里尔字母书写时,它会正确显示。
答案1
看起来你正在谈论RFC 2047:电子邮件标头的 MIME 编码。此后,更多的 RFC 对该 RFC 进行了扩充,以允许更多字符集并可选择包含语言规范。
由于最初的电子邮件和 MIME 规范包含标头仅包含严格的 US-ASCII 的假设,因此标头编码与邮件正文的 MIME 编码是完全独立的问题。
格式为:
=? <character-set> [*language] ? <encoding-letter> ? <text> ?=
<encoding-letter>
要么是 Q(表示可引用打印),要么是 B(表示 base64 编码)。如果该消息看起来完全是乱码,我假设您看到的是 base64。字符集名称和编码字母都不区分大小写。
所以你可能会看到:
Subject: =?utf-8?b?SWYgeW91IGNhbiByZWFkIHRoaXMsIHlvdSB1bmRlcnN0b29kIHRoZSBleGFtcGxlLgo=?=
或者添加语言 ID:
Subject: =?utf-8*en?b?SWYgeW91IGNhbiByZWFkIHRoaXMsIHlvdSB1bmRlcnN0b29kIHRoZSBleGFtcGxlLgo=?=
手动解码示例:
$ echo "SWYgeW91IGNhbiByZWFkIHRoaXMsIHlvdSB1bmRlcnN0b29kIHRoZSBleGFtcGxlLgo=" | base64 -d
If you can read this, you understood the example.
事实上,您现有的 Procmail 脚本包括强制标记字符集编码iso-8859-1
,US-ASCII
并且UNKNOWN-8BIT
aswindows-1251
表明您的实际问题可能是错误标记的字符编码。换句话说:
- 旧的电子邮件客户端发出
windows-1251
西里尔字母,但没有这样标记它们,也可能在标题中 - 在此过程中,电子邮件经过的邮件服务器要么没有正确声明它可以干净地处理 8 位邮件编码,要么热衷于强制执行除普通 US-ASCII 之外的所有字符集的标签。
在这种情况下,MTA 需要对 8 位字符进行编码和标记才能传递邮件。但如果 8 位字符未标记,则只有始发邮件客户端才能确定字符集实际是什么。
事后标记字符集的问题在于,识别字符集可能需要人类水平的理解,以了解内容解释为特定字符集是否有意义。所以你最终会使用启发法,这有时会是错误的。
例如,如果您收到一封实际上正确编码为 的电子邮件iso-8859-1
,您的脚本会将其错误标记为windows-1251
,导致任何北欧/西欧重音字符显示为随机无意义的西里尔字母。但如果这种情况比收到windows-1251
错误标记为 的编码消息更为罕见iso-8859-1
,那么您可能会选择接受这种风险,这也没关系。
我认为您必须调查有问题的消息,以找出它们的Subject:
标头实际上是如何编码的。他们是:
- 普通无标签
windows-1251
? - 实际上是有效的
base64
UTF-8 编码吗? - 或者
windows-1251
已被base64
编码并错误标记为 UTF-8?
不幸的是procmail
,它的同伴formail
可能不足以获取Subject:
未编码形式的标头。他们已自2001年起不再维护, 和甚至他们的作者现在也建议转向其他事情。但如果您procmail
现在想继续使用,您将需要类似以下脚本的内容:
https://github.com/akkana/scripts/blob/master/decodemail.py
我大约有 10 年没有做过重要的procmail
脚本编写了,所以下面的示例可能是错误的,或者可能有更好的方法来做到这一点。但这也许有助于解释如何解决问题......
您必须首先解码Subject:
标头的内容并将其存储到变量中:
:0 h
SUBJDECODED=| decodemail.py Subject:
:0 h
SUBJWASRAW=| formail -xSubject: | recode windows-1251..UTF-8
要纠正错误标记的编码,您可能必须将字符集从实际的字符集重新编码为系统使用的 UTF-8:
SUBJWASWIN1251=`echo "$SUBJDECODED" | recode windows-1251..UTF-8`
如果有多种可能的编码,您可能必须创建多个这样的变量。
然后您可以按主题的任何版本进行匹配:
:0
* SUBJWASRAW ?? your-subject-regexp-here
{
# Here the subject was raw windows-1251 without any encoding at all.
# The variable has it converted to valid UTF-8 used by this system,
# so now the header can be rewritten in an useful form.
# (This example leaves the subject as raw unlabelled UTF-8 which
# may or may not be acceptable to whatever you use to view your email with.
# But on modern RFC 6532 compliant mail clients
# in a system that uses UTF-8 throughout it may actually be OK.)
:0 f
| formail -i "Subject: $SUBJWASRAW"
}
:0
* SUBJWASWIN1251 ?? your-subject-regexp-here
{
# regexp matched, so we know the subject was windows-1251
# mislabeled as UTF-8. Fix it.
:0 f
| formail -i "Subject: $SUBJWASWIN1251"
}
:0
* SUBJDECODED ?? your-subject-regexp-here
{
# regexp matched to subject decoded according to existing label
# so we know that it was validly labelled. But it still needs to
# be rewritten as it may have been something other than UTF-8.
:0 f
| formail -i "Subject: $SUBJDECODED"
}
# Any further rules should be able to match on the subject as usual.
注意:your-subject-regexp-here
正则表达式不应包含^Subject:.*
前缀,因为变量只会包含价值标题的Subject:
。