procmail 西里尔文转换

procmail 西里尔文转换

我编写了一个脚本,用于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-1US-ASCII并且UNKNOWN-8BITaswindows-1251表明您的实际问题可能是错误标记的字符编码。换句话说:

  • 旧的电子邮件客户端发出windows-1251西里尔字母,但没有这样标记它们,也可能在标题中
  • 在此过程中,电子邮件经过的邮件服务器要么没有正确声明它可以干净地处理 8 位邮件编码,要么热衷于强制执行除普通 US-ASCII 之外的所有字符集的标签。

在这种情况下,MTA 需要对 8 位字符进行编码和标记才能传递邮件。但如果 8 位字符未标记,则只有始发邮件客户端才能确定字符集实际是什么。

事后标记字符集的问题在于,识别字符集可能需要人类水平的理解,以了解内容解释为特定字符集是否有意义。所以你最终会使用启发法,这有时会是错误的。

例如,如果您收到一封实际上正确编码为 的电子邮件iso-8859-1,您的脚本会将其错误标记为windows-1251,导致任何北欧/西欧重音字符显示为随机无意义的西里尔字母。但如果这种情况比收到windows-1251错误标记为 的编码消息更为罕见iso-8859-1,那么您可能会选择接受这种风险,这也没关系。

我认为您必须调查有问题的消息,以找出它们的Subject:标头实际上是如何编码的。他们是:

  • 普通无标签windows-1251
  • 实际上是有效的base64UTF-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:

相关内容