マルチパート構造のメールヘッダにおける情報抽出について

コメント

8件のコメント

  • 正式なコメント
    Ichiro Takahashi

    メールデータのご提供ありがとうございます。

    ご希望の操作を少し一般化して、以下のようなライブラリオブジェクトを作成してみました。

    import re

    def filter_parts(parsed_mail, type_pattern=None, is_attachment=None):
        """
        mail_parse() の結果から指定した形式のパートを抽出する

        Args:
            parsed_mail(dict[str]): mail_parse() 結果の辞書データ 
            type_pattern(str): 抽出するパートを Content-Type で指定する
                '^text/html' などと正規表現で指定する
            is_attachment(bool): 添付ファイルパートを抽出するか指定する
                True: 添付ファイルパートだけを抽出する
                False: 添付ファイルパート以外を抽出する
                上記以外: 添付ファイルパートであるかは検知しない
        Returns:
            list[str]: 条件にマッチしたパートのリスト
        """
        if type_pattern:
            type_pattern = re.compile(type_pattern)
        parts = []
        def _filter(part):
            if part.get('Is-Multipart', False):
                for subpart in part['Body']:
                    _filter(subpart)
                return
            if type_pattern:
                content_type = part.get('Content-Type', '')
                if not type_pattern.match(content_type):
                    return
            if isinstance(is_attachment, bool):
                has_filename = bool(part.get('Filename', ''))
                if is_attachment ^ has_filename:
                    return
            parts.append(part)
        _filter(parsed_mail)
        return parts

    このライブラリオブジェクトを例えば「mail_lib」という名前で作成しておき、同じディレクトリにあるジョブフローから以下のように呼び出してみてください。ジョブフローのパラメータ raw_mail_txt にはヘッダを含むメール全体テキストを渡してください。

    |raw_mail_txt|

    [filter_parts = ./mail_lib.filter_parts] ->
    [parsed = mail_parse(raw_mail_txt)] ->

    print("----- HTML パートの抽出 -----") ->
    [html_parts = filter_parts(parsed, '^text/html')] ->
    print(html_parts) ->

    print("----- TEXT 形式の添付ファイルの抽出 -----") ->
    [attach_parts = filter_parts(parsed, '^text', is_attachment=true)] ->
    print(attach_parts)

    filter_parts() 関数が抽出したデータは mail_parse() で得られる各パートと同じ構造です。このサンプルを実行すると、HTML パートと、TEXT 形式の添付ファイルを抽出できているかと思います。

    参考になさってみてください。

    コメントアクション パーマリンク
  • Ichiro Takahashi

    フィックスポイントの高橋です。

    メールを送付し、本スクリプトを実行時、下記エラーが確認されました。
    フィールドエラー: 不正なオブジェクト "Content-Type": string indices must be integers'

    おそらくmail_bodyの一要素目である「Content-Type」がpartに格納された際に生じたエラーとみられます。

    リンク先にサンプルとして提示したジョブフローでは、簡単にするためメールのマルチパートが入れ子構造になっている場合などには対応していません。

    送付されたメールのヘッダを含んだ全文を張り付けていただき、判定したい(または抽出したい)条件を示していただければ、また別のサンプルをご提示できるかもしれません。

    (なお、本処理は特に JSON とは関係がありませんので、タイトルと補足部分については意図を読み取りかねますが、マルチパートの構造を JSON と見立てておられるのかと推測しました)

    以上、参考になさってください。

    0
    コメントアクション パーマリンク
  • 石山潤

    リンク先にサンプルとして提示したジョブフローでは、簡単にするためメールのマルチパートが入れ子構造になっている場合などには対応していません。

    送付されたメールのヘッダを含んだ全文を張り付けていただき、判定したい(または抽出したい)条件を示していただければ、また別のサンプルをご提示できるかもしれません。

    ご回答ありがとうございます。

    ヘッダ情報の添付が漏れていました。こちらがヘッダとなります。

    Body{
        'Content-Type': 'multipart/mixed;\r\n\tboundary="----=_NextPart_001_006C_01DA9002.31E9C830"',
        'Is-Multipart': True,
        'Body':
            [
                {
                    'Content-Type': 'multipart/alternative;\r\n\tboundary="----=_NextPart_002_006D_01DA9002.31E9C830"',
                    'Is-Multipart': True,
                    'Body': 
                    [
                        {
                            'Content-Type': 'text/plain;\r\n\tcharset="iso-2022-jp"',
                            'Content-Transfer-Encoding': '7bit',
                            'Is-Multipart': False,
                            'Body': '添付ファイルテスト\r\n\r\n',
                            'Filename': None
                        }, 
                        {
                            'Content-Type': 'text/html;\r\n\tcharset="iso-2022-jp"',
                            'Content-Transfer-Encoding': 'quoted-printable',
                            'Is-Multipart': False,
                            'Body': '【HTML情報が含まれる】',
                            'Filename': None
                        }
                    ]
                },
                {
                    'Content-Type': 'text/plain; name="添付ファイルのタイトルです。.txt"',
                    'Content-Transfer-Encoding': '7bit',
                    'Content-Disposition': 'attachment; filename="添付ファイルのタイトルです。.txt"',
                    'Is-Multipart': False,
                    'Body': '',
                    'Filename': '添付ファイルのタイトルです。.txt'
                }
            ]
    }

     

    (なお、本処理は特に JSON とは関係がありませんので、タイトルと補足部分については意図を読み取りかねますが、マルチパートの構造を JSON と見立てておられるのかと推測しました)

    こちら、読み替えいただいた意図で問題ございません。ありがとうございます。

    0
    コメントアクション パーマリンク
  • Ichiro Takahashi

    データのご提示ありがとうございます。やはりマルチパートが入れ子構造になっているようですので、先に提示させていただいたサンプルジョブフローでは適切に扱うことはできません。

    お知りになりたいこととしては、このような構造を持つメールから、添付ファイルの情報(名前と内容)を取得したい、ということでよろしかったでしょうか?

    ただ、本階層には最終的に抽出したいFilenameが含まれていません。

    また、入れ子になったパートに含まれる添付ファイルについて、たしかに Filename が含まれていないように見受けられます。こちらを調査するには、mail_parse() 前の元データが必要になりますが、ご提供いただくことは可能でしょうか。

    0
    コメントアクション パーマリンク
  • 石山潤

    お知りになりたいこととしては、このような構造を持つメールから、添付ファイルの情報(名前と内容)を取得したい、ということでよろしかったでしょうか?

    はい、ご認識の通りです。

    また、一旦は添付ファイル名称を抽出できれば問題ございません。

     

    ただ、本階層には最終的に抽出したいFilenameが含まれていません。

    また、入れ子になったパートに含まれる添付ファイルについて、たしかに Filename が含まれていないように見受けられます。こちらを調査するには、mail_parse() 前の元データが必要になりますが、ご提供いただくことは可能でしょうか。

    Filenameについては、昨日展開しましたヘッダ内Bodyの最後にある以下情報です。

    こちらのtxtファイル名称を抽出できれば問題ございません。

    'Filename': '添付ファイルのタイトルです。.txt'

     

    また、メールヘッダの元データが必要な場合、ユーザ情報が含まれますのでお手数ですがメールでお送りさせていただいてもよろしいでしょうか。

    0
    コメントアクション パーマリンク
  • Ichiro Takahashi

    また、メールヘッダの元データが必要な場合、ユーザ情報が含まれますのでお手数ですがメールでお送りさせていただいてもよろしいでしょうか。

    では、お手数ですが、 takahashi+zendesk@fixpoint.co.jp までお送りいただけますでしょうか。

    0
    コメントアクション パーマリンク
  • 石山潤

    承知しました。ありがとうございます。

    0
    コメントアクション パーマリンク
  • 石山潤

    ジョブフローサンプルの作成ありがとうございます。

    参考にさせていただきます。

    0
    コメントアクション パーマリンク

サインインしてコメントを残してください。