[Please do not mail me a copy of your followup]
I fixed a small problem in my no-multipart-alternative.pl script
today. If I received a mail message containing multiple text/plain
parts, where some of the text/plain parts had filenames, then the
script would erroneously collapse all the text/plain parts into a
single text/plain part. This meant that a text/plain mail with a
text/plain attachment would essentially lose the attachment.
I adjusted the script to collapse multiple text/plain parts only when
none of them has a filename specified.
Multiple text/plain parts can occur when a multipart/alternative
text/{plain,html} message is sent to a mailing list and the mailing
list software appends a text/plain signature part, giving you a
message structure like this:
multipart/mixed
multipart/alternative
text/plain
text/html
text/plain
As long as the text/plain parts don't have associated filenames
(indicating that they are not intended to be separate attachments), my
script will collapse this to a single text/plain Content-Type,
stripping away the text/html alternative and then collapsing all the
text/plain parts into a single text/plain message body.
Attached (as a text/plain attachment!) is the updated script.
--
"The Direct3D Graphics Pipeline" -- DirectX 9 draft available for download
<http://legalizeadulthood.wordpress.com/the-direct3d-graphics-pipeline/>
Legalize Adulthood! <http://legalizeadulthood.wordpress.com>
[
no-multipart-alternative.pl 2K ]
#!/usr/local/bin/perl -w
use MIME::Parser;
use MIME::Head;
use MIME::Body;
use MIME::QuotedPrint;
sub constructParser {
my $parser = new MIME::Parser;
$parser->output_to_core(1);
$parser->decode_headers(1);
$parser->decode_bodies(1);
$parser->extract_uuencode(1);
return $parser;
}
sub isPlainTextAlternative($)
{
my($entity) = @_;
my $contentType = $entity->head->mime_type;
if (($contentType eq 'multipart/alternative')
&& scalar($entity->parts) == 2)
{
my $part1 = $entity->parts(0);
my $type1 = $part1->mime_type;
my $part2 = $entity->parts(1);
my $type2 = $part2->mime_type;
return (($type1 eq 'text/plain') && ($type2 eq 'text/html'))
|| (($type1 eq 'text/html') && ($type2 eq 'text/plain'));
}
return 0;
}
sub removeHtmlAlternative($)
{
my($entity) = @_;
$entity->parts([ $entity->parts(
($entity->parts(0)->mime_type eq 'text/plain') ? 0 : 1) ]);
$entity->make_singlepart;
}
sub isMultiplePlainText($)
{
my($entity) = @_;
local($_);
if (scalar($entity->parts) > 1)
{
foreach ($entity->parts)
{
if ($_->mime_type ne 'text/plain')
{
return 0;
}
# if additional text/plain sections are file attachments,
# then leave it alone
if (defined $_->head->mime_attr('content-type.name'))
{
return 0;
}
}
return 1;
}
return 0;
}
sub collapsePlainText($)
{
my($entity) = @_;
local($_);
my($body) = '';
foreach ($entity->parts)
{
$body .= $_->bodyhandle->as_string . "\n";
}
my($newEntity) = MIME::Entity->build(Type => 'text/plain',
Encoding => '8bit', Data => $body);
$entity->parts([ $newEntity ]);
$entity->make_singlepart;
}
sub processEntity($);
sub processEntity($)
{
my($entity) = @_;
local($_);
foreach ($entity->parts)
{
processEntity($_);
}
if (isPlainTextAlternative($entity))
{
removeHtmlAlternative($entity);
}
if (isMultiplePlainText($entity))
{
collapsePlainText($entity);
}
}
sub main {
my $parser = constructParser;
my $entity = $parser->parse(\*STDIN) or die "parse failed\n";
processEntity($entity);
$entity->print(\*STDOUT);
}
main;