Perl анализирует тело письма без частей, используя MIME :: Parser - PullRequest
0 голосов
/ 05 июня 2019

У меня есть Perl-скрипт, который использует MIME :: Email для разбора электронных писем, полученных от stdin, но он не работает на электронных письмах без частей. У меня нет возможности изменять электронные письма до их отправки.

Я бы хотел иметь возможность идентифицировать значительную часть письма независимо от того, является ли он HTML или текстом, и сохранить его в буфере для последующей обработки. Многие из этих писем принадлежат списку рассылки, который каким-то образом генерируется автоматически.

Иногда кажется, что у них только один заголовок "Content-Type:" без границ.

MIME-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit

В других случаях они имеют несколько текстовых / простых частей, где один - это тело письма, а другой - подпись.

После этого есть несколько других строк заголовка, но затем тело просто отображается без каких-либо граничных маркеров.

Это мое сообщение от двухлетней давности, показывающее, как мне удалось со временем разобраться, как разбирать большинство писем по частям. Разбор электронной почты с электронной почтой :: MIME и multipart / смешанный с частями

use strict;
use MIME::Parser;
use MIME::Entity;
use Email::MIME;
use Email::Simple;
my $parser = MIME::Parser->new;
$parser->extract_uuencode(1);
$parser->extract_nested_messages(1);
$parser->output_to_core(1);
my $buf;
while(<STDIN> ){
        $buf .= $_; 
}

my $entity = $parser->parse_data($buf);

$entity->dump_skeleton;
my $num_parts = $entity->parts;
for (my $i=0; $i < $num_parts; $i++) {
    my $part = $entity->parts($i);
    my $content_type = $part->mime_type;
    my $body = $part->as_string;

    print "body: $body\n";
}

Основной текст никогда не печатается. Только следующее из dump_skeleton:

Content-type: text/plain
Effective-type: text/plain
Body-file: NONE
Subject: Security update 

Мне бы очень хотелось, чтобы у меня была возможность изменить свой существующий скрипт (как показано в предыдущем сообщении об обмене стеками), чтобы можно было печатать подобные письма без каких-либо границ.

Это плохое форматирование? Мне не удалось найти какие-либо примеры библиотеки, которую можно использовать для надежной печати основного текста, темы и других основных заголовков электронного письма без сложных шагов по анализу всего сообщения по частям.

Я знаю, что mimeexplode может это сделать, но я не могу понять, как. Мне нужно хранить почтовое тело в буфере для манипулирования, поэтому использование программы командной строки, такой как mimeexplode, было бы обходным способом сделать это в любом случае.

1 Ответ

3 голосов
/ 05 июня 2019

Мне не совсем ясно, чего вы пытаетесь достичь, так как вы только публикуете код, а не намерение, стоящее за ним, достаточно подробно.Но вы используете parts для проверки сообщения, которое четко задокументировано для возврата частей multipart/* или аналогичных (то есть message/rfc822) и не обрабатывает отдельные сообщения:

... возвращает массив всех частей, возвращает пустой массив, если таковых нет (например, если это сообщение одной части или вырожденная составная часть) .В скалярном контексте это возвращает вам количество частей.

Если вы хотите просто получить все части, включая автономные «части» (то есть одну сущность, которая не является частью чего-либо), просто используйте parts_DFS как в следующем примере, который печатает тело для всех сущностей, которые имеют ненулевое тело:

use MIME::Parser;
my $parser = MIME::Parser->new;
my $entity = $parser->parse(\*STDIN);
for my $part ($entity->parts_DFS) {
    defined(my $body = $part->bodyhandle) or next; # has no body, likely multipart or similar
    print "body: ".$body->as_string."\n";
}

РЕДАКТИРОВАТЬ: если вы обновили вопрос, вы ищете не все детали, аосновная текстовая часть.Нелегко определить фактическую часть main , но вы можете попытаться использовать первую часть text/*, которая является встроенной.Это, вероятно, будет выглядеть примерно так:

use MIME::Parser;
my $parser = MIME::Parser->new;
my $entity = $parser->parse(\*STDIN);
for my $part ($entity->parts_DFS) {
    defined(my $body = $part->bodyhandle) or next; # has no body, likely multipart or similar
    if (my $disp = $part->head->get('content-disposition')) {
        next if $disp !~ m{inline}i;
    }
    print "body: ".$body->as_string."\n";
    last;
}
...