[Mimedefang] Problem with message rewrite and messages with more than one Content-Type header

Michael Sims michaels at crye-leike.com
Thu Apr 24 21:30:01 EDT 2003


I'm using a rather unusual mimedefang-filter that works great 99% of the
time, but I just discovered a problem with it this morning.  I've tracked
the problem down to a poor assumption on my part, and I was hoping to get
some feedback from the list on how to solve it.

I'll warn up front that I have a very unusual filter, and I'm probably doing
a lot more with it than I should be...  Also what I'm attempting might not
be possible, and I'm more than willing to accept that... :)

Inside my filter_end() (relevant portion is at the bottom of this message),
if a message is considered spam by SpamAssassin, I modify the message body
to include an HTML spam warning, a text version of the same warning, and the
complete original message as a message/rfc822 part.  I do this by munging
the $entity object passed to filter end and then calling action_rebuild().
(I was doing this before replace_entire_message() was available, but using
this sub instead still does not fix my issue.)

I set the MIME type of $entity to multipart/mixed and change the boundary,
since the message/rfc822 part might itself be a multipart/mixed message, and
I have to make sure that my altered message has a new, different boundary.

The problem occurs when the original message contains more than one
"Content-Type" header.  For example, I received a piece of spam that
contained these two lines in its header:

Content-Type: text/html; charset=ISO-8859-1
Content-Type: text/html; charset=iso-8859-1

When I modify the content type of $entity, it appears that only the first
Content-Type header is being changed, and I end up with this:

Content-Type: multipart/mixed;
boundary="----------=_1051216770-7897-20862148200"
Content-Type: text/html; charset=iso-8859-1

Outlook (surprise, surprise) honors the last Content-Type header, and I end
up with a very poorly rendered message that has a lot of visible MIME
meta-info interspersed among poorly formatted HTML.

At first I thought the problem might lie with the MIME::Head module.  I
called $entity->head->as_string as saved this to a debug log file so I could
see what headers MIME::Head thought the message had.  I then discovered that
these headers differed from that of the original message.

I started looking around in mimedefang.pl and it looks like it actually
changes the MIME type of $entity to one of three sensible types.
Additionally, I don't believe all of the headers are present in $entity, and
I suspect that changes to $entity are merged back into the original message,
rather than completely replacing it.

I can't seem to come up with a way to work around this problem, or make sure
that the final message only contains one Content-Type header, at least not
without making changes to mimedefang.pl, which I really don't want to do.

Thanks to anyone who has managed to read this far, and if I'm not explaining
myself very well please ask and I will clarify as much as possible.  Any
feedback is appreciated.  Here is the relevant excerpt from my filter:

-----CUT HERE-----
# Build container object for original message
my $container = MIME::Entity->build(
  Type        => 'message/rfc822',
  Description => 'Original Message',
  Data        => [ "" ]
);

# Build new MIME::Entity containing original message
# by parsing the full message text with MIME::Parser
my $parser = new MIME::Parser;
open(IN, '< ./INPUTMSG');
my $originalMsg = $parser->parse(\*IN);
close(IN);

# Add information about the last relay to the included
# message
$originalMsg->head->replace('X-Relay-Addr', $RelayAddr);
$RelayHostname ||= 'N/A';
$originalMsg->head->replace('X-Relay-Host', $RelayHostname);
$originalMsg->head->replace('X-Relay-Time', scalar localtime);

# Add original message to container entity...
$container->add_part($originalMsg);

# Build the SA report
my $reportPart = MIME::Entity->build(
  Type        => 'text/plain',
  Description => 'Crye-Leike Spam Warning (TXT)',
  Data        => [ getSaReportTxt($report) ]
);

my $htmlPart = MIME::Entity->build(
  Type        => 'text/html',
  Description => 'Crye-Leike Spam Warning (HTML)',
  Data        => [ getSaReportHtml($report) ]
);

# Replace all existing parts of the current message with
# the SA report
$entity->parts([$htmlPart, $reportPart]);

# Change the MIME type to multipart/mixed and rewrite the
# MIME boundary so that it's different from the one in the
# attached original message
$entity->head->mime_attr('content-type' => 'multipart/mixed');

$entity->head->mime_attr(
  'content-type.boundary'
    => "----------=_".scalar(time)."-$$-20862148200"
);

# Add the container and rebuild the message
$entity->add_part($container);
action_change_header('Subject', "[SPAM] ($hits): $Subject");
action_rebuild();
-----CUT HERE-----




More information about the MIMEDefang mailing list