#1
  1. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    May 2007
    Posts
    765
    Rep Power
    928

    Mail::Message::Body and Binary Data


    I'm trying to attach a binary file to a Mail::Message object, constructing the multi-part body using:

    Code:
    $body->attach(Mail::Message::Body::File->new( file => $file, mime_type => $type ));
    Where $file is the path to a file, and $type is 'application/octet-stream'. When tearing apart the resulting message, I'm finding that the content of $file underwent a CRLF<->LF translation.

    How do I prevent this?
    sub{*{$::{$_}}{CODE}==$_[0]&& print for(%:: )}->(\&Meh);
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    May 2007
    Posts
    765
    Rep Power
    928
    More complete example of the issue. The hex dump of the attachment yields "ff0aff0dff0a0dff0aff", where the original file contained 0d0a.

    Code:
    use Mail::Message;
    
    open OUT, '>', 'example.dat';
    binmode OUT;
    print OUT "\xFF\x0a\xFF\x0d\xFF\x0a\x0d\xFF\x0d\x0a\xFF";
    close OUT;
    
    $mail = Mail::Message->build(
        From => 'me@example.com',
        To => 'you@example.com',
        Subject => 'Bug in Mail::Message::Body::File',
        data => ['See attached file']
    );
    
    $body = $mail->body;
    $body = $body->attach( Mail::Message::Body::File->new(
        file => 'example.dat',
        mime_type => 'application/octet-stream'
    ) );
    $mail->body($body);
    
    
    open OUT, '>', 'example.mail';
    $mail->print( \*OUT );
    close OUT;
    
    open IN, '<', 'example.mail';
    $newmail = Mail::Message->read( \*IN );
    close IN;
    
    @parts = $newmail->parts;
    
    print "- - - - - - - - - - - - - - - - -\n";
    for (@parts) {
        $data = $_->decoded();
        hexdump( $data );
        print "- - - - - - - - - - - - - - - - -\n";
    }
    
    sub hexdump {
        my $data = shift;
    
        while( length $data ) {
            $line = substr $data, 0, 16, '';
            $hex  = unpack 'H*', $line;
            $line =~ tr/\x20-\x7e/./c;
            printf "%-32s | %s\n", $hex, $line;
        }
    }
    sub{*{$::{$_}}{CODE}==$_[0]&& print for(%:: )}->(\&Meh);
  4. #3
  5. !~ /m$/
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    May 2004
    Location
    Reno, NV
    Posts
    4,223
    Rep Power
    1809
    I tried your code and got the warning:
    Attempt to use reference as lvalue in substr
    Code:
    for (@parts) {
        $data = $_->decoded();
        hexdump( $data );
        print "- - - - - - - - - - - - - - - - -\n";
    }
    $data is a Mail::Message::Body::Lines object, not text, or an array of lines.

    I think what you need is access to the attached file, not to the body itself. Appears to be accessible through a file method. I changed the code to this:
    Code:
    print "- - - - - - - - - - - - - - - - -\n";
    	
    for (@parts) {
    	my $body = $_->decoded();
    	
    	my $file = $body->file;
    	while (<$file>) {
    		hexdump($_);
    	}
    	
    	print "- - - - - - - - - - - - - - - - -\n";
    }
    
    sub hexdump {
        my $line = shift;
        
        my $l = substr $line, 0, 16, '';
        my $hex  = unpack 'H*', $l;
        $l =~ tr/\x20-\x7e/./c;
        printf "%-32s | %s\n", $hex, $l;
    }
    My result:
    Code:
    - - - - - - - - - - - - - - - - -
    5365652061747461636865642066696c | See attached fil
    - - - - - - - - - - - - - - - - -
    ff0a                             | ..
    ff0dff0a                         | ....
    0dff0d0a                         | ....
    ff                               | .
    - - - - - - - - - - - - - - - - -
    Might not be quite what you want, but the missing character is back for me.
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    May 2007
    Posts
    765
    Rep Power
    928
    This is weird,

    I tried your code and a few variations (using $data->file->getlines and $data->string) rather that letting the overload stringify it and got my originally buggy output in each case.

    What version of Mail::Box are you running?
    sub{*{$::{$_}}{CODE}==$_[0]&& print for(%:: )}->(\&Meh);
  8. #5
  9. !~ /m$/
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    May 2004
    Location
    Reno, NV
    Posts
    4,223
    Rep Power
    1809
    Version 2.110 on Mac OS X
  10. #6
  11. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    May 2007
    Posts
    765
    Rep Power
    928
    Ah, isn't OSX the version where the text/binary distinction on files was eliminated? If so, then the world makes sense again.
    sub{*{$::{$_}}{CODE}==$_[0]&& print for(%:: )}->(\&Meh);

IMN logo majestic logo threadwatch logo seochat tools logo