Archived Forum Post

Index of archived forum posts

Question:

Using chilkat::CkDkim to dkim-sign a message, and write the signed message to a file, when input message may (or may not) be UTF-8 encoded (perl)

Jul 22 '15 at 10:54

The function dkimsign() at the end of this post can be used to load a .eml message from a file ($infile), dkim-sign the message, and write the signed message to another file ($outfile). It works as expected if $infile contains a message that is iso-8859-1 encoded. However, if the message is UTF-8 encoded, the character encoding in $outfile becomes garbled.

If $infile is UTF-8 encoded, this problem can be solved by applying $email2->put_Utf8(1); near the end of the script, before the signed message is written to $outfile.

However, in cases where $infile may or may not be $utf-8 encoded, this begs the question, how to know when to apply $email2->put_Utf8(1);?

I attempted to determine whether or not $infile is UTF-8 encoded using get_Utf8(), using the test script below:

use strict;
use warnings;
use chilkat;

my($email,$success,$infile,$utf8);
$infile="~/in.txt";

  #create chilkat::CkEmail object and load raw email into it from file
  $email = new chilkat::CkEmail();
  $success = $email->LoadEml($infile);
  if ($success != 1) {
    print $email->lastErrorText() . "\n";
    exit;
  }
  $utf8=$email->get_Utf8();

  print "utf8: " . $utf8 . "\n";

However, this script returns 0 regardless of whether ~/in.txt is UTF-8 encoded or not.

So, the question is: How can it be determined whether or not to apply the $email2->put_Utf8(1) method when writing the signed message to a file, given a source message which may or may not be using Utf-8 encoding?

Environment: Chilkat 9.5.0.49, perl 5, version 20, subversion 2 (v5.20.2) built for x86_64-linux-gnu-thread-multi, Debian 8.0

sub dkimsign { my($infile, $outfile, $dkimdomain, $dkimselector, $dkimpkfile)=@_; my($email, $success, $mailman, $mimeData, $dkim, $password, $dkimSignedMime, $email2, $utf8); ###create chilkat::CkEmail object and load raw email into it from file $email = new chilkat::CkEmail(); $success = $email->LoadEml($infile); if ($success != 1) { print $email->lastErrorText() . "n"; exit; }

    #print $email->getMime();   #test that email was loaded correctly

    ###create chilkat::CkMailMan object and use it to represent email in chilkat::CkEmail object as a chilkat::CkByteData mimedata object
    $mailman = new chilkat::CkMailMan();
    $success = $mailman->UnlockComponent("Anything for 30-day trial");
    if ($success != 1) {
            print $mailman->lastErrorText() . "\n";
            exit;
    }

    $mimeData = new chilkat::CkByteData();
    $success = $mailman->RenderToMimeBytes($email,$mimeData);
    if ($success != 1) {
            print $mailman->lastErrorText() . "\n";
            exit;
    }

    ###create chilkat::CkDkim object and use it to dkim-sign the email $mimeData object
    $dkim = new chilkat::CkDkim();
    $success = $dkim->UnlockComponent("Anything for 30-day trial");
    if ($success != 1) {
            print $dkim->lastErrorText() . "\n";
            exit;
    }

    $dkim->put_DkimDomain($dkimdomain);
    $dkim->put_DkimSelector($dkimselector);
    $password = "optionalPassword";
    $success = $dkim->LoadDkimPkFile($dkimpkfile, $password);
    if ($success != 1) {
            print $dkim->lastErrorText() . "\n";
            exit;
    }

    $dkimSignedMime = new chilkat::CkByteData();
    $success = $dkim->AddDkimSignature($mimeData, $dkimSignedMime);
    if ($success != 1) {
            print $dkim->lastErrorText() . "\n";
            exit;
    }

    ###create chilkat::CkEmail object and use it to output dkim-signed message
    $email2 = new chilkat::CkEmail();
    $success = $email2->SetFromMimeBytes($dkimSignedMime);
    if ($success != 1) {
            print $email2->lastErrorText() . "\n";
            exit;
    }

    $email2->put_Utf8(1);
    open (fh1, ">" . $outfile);
    print fh1 $email2->getMime();
    close (fh1);

}


Accepted Answer

Thanks!

Rather than writing the file by opening/creating a new file and writing the output of $email2->getMime(), call $email2->SaveEml($outPath) instead.

MIME files (.eml) are tricky in that the character encoding used for reading/writing may need to match what's specified in a MIME header if an 8bit encoding is used. If all encodings are 7bit (i.e. quoted-printable, base64, etc) and all 8bit chars in MIME header fields are Q/B encoded, then the entire file is us-ascii and there is no difference between ANSI (iso-8859-1) and utf-8 (because 7bit means only us-ascii chars are present).

If an 8bit encoding is used, then the text parts of the MIME that are 8bit would need to use the charset specified in the MIME header when writing, and a MIME reader would need to interpret the bytes according to that charset. It can be even more complicated if binary MIME is used, because now you'll have bytes that don't represent chars and these should just be kept as-is. In a nutshell, let Chilkat do the reading/writing of the MIME. If the MIME is known to be entirely 7bit, then you're safe in reading/writing it yourself..