web-dev-qa-db-ja.com

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
Gneiss

あなたが話しているように見えます RFC 2047:電子メールヘッダーのMIMEエンコーディング 。その後、さらにRFCがこのRFCを拡張して、より多くの文字セットを許可し、オプションで言語仕様を含めるようになりました。

初期の電子メールとMIMEの仕様には、ヘッダーに厳密なUS-ASCIIのみが含まれるという前提が含まれていたため、ヘッダーのエンコードはメッセージ本文のMIMEエンコードとは完全に別の問題です。

形式は次のとおりです。

=? <character-set> [*language] ? <encoding-letter> ? <text> ?=

<encoding-letter>は、quoted-printableの場合はQ、base64エンコーディングの場合はBになります。メッセージが完全に意味不明であると思われる場合は、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-8BITwindows-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-エンコードされ、UTF-8として誤ってラベル付けされたbase64

残念ながら、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ヘッダーのvalueのみが含まれるため、^Subject:.*正規表現にはSubject:プレフィックスを含めないでください。

2
telcoM