TNEF(3)
okay bestie, gather round π this is TNEF(3), the User Contributed Perl Documentation page for Convert::TNEF β the Perl module to read TNEF files. no cap, the whole page is right here and weβre gonna get you comfy with it. β¨
πΈ NAME πΈ
Convert::TNEF β Perl module to read TNEF files. yes, thatβs the name, short and iconic. π
π¦ SYNOPSIS π¦
hereβs the group-chat cheat sheet, copy-paste exact:
use Convert::TNEF;
$tnef = Convert::TNEF->read($iohandle, \%parms)
or die Convert::TNEF::errstr;
$tnef = Convert::TNEF->read_in($filename, \%parms)
or die Convert::TNEF::errstr;
$tnef = Convert::TNEF->read_ent($mime_entity, \%parms)
or die Convert::TNEF::errstr;
$tnef->purge;
$message = $tnef->message;
@attachments = $tnef->attachments;
$attribute_value = $attachments[$i]->data($att_attribute_name);
$attribute_value_size = $attachments[$i]->size($att_attribute_name);
$attachment_name = $attachments[$i]->name;
$long_attachment_name = $attachments[$i]->longname;
$datahandle = $attachments[$i]->datahandle($att_attribute_name);
π DESCRIPTION π
okay so: TNEF stands for Transport Neutral Encapsulation Format, and if youβve ever been unfortunate enough to receive one of these files as an email attachment, you may want to use this module. literally a whole βmaβam, why is this in my inboxβ moment. π
read() takes as its first argument any file handle open for reading. The optional second argument is a hash reference which contains one or more of the following keys:
π§Έ the optional \%parms hash keys π§Έ
output_dirβ Path for storing TNEF attribute data kept in files (default: current directory).output_prefixβ File prefix for TNEF attribute data kept in files (default:'tnef').output_to_coreβ TNEF attribute data will be saved in core memory unless it is greater than this many bytes (default: 4096). May also be set to'NONE'to keep all data in files, or'ALL'to keep all data in core.buffer_sizeβ Buffer size for reading in the TNEF file (default: 1024).debugβ If true, outputs all sorts of info about what theread()function is reading, including the raw ascii data along with the data converted to hex (default: false).display_after_errβ If debug is true and an error is encountered, reads and displays this many bytes of data following the error (default: 32).debug_max_displayβ If debug is true then read and display at most this many bytes of data for each TNEF attribute (default: 1024).debug_max_line_sizeβ If debug is true then at most this many bytes of data will be displayed on each line for each TNEF attribute (default: 64).ignore_checksumβ If true, will ignore checksum errors while parsing data (default: false).
read() returns an object containing the TNEF βattributesβ read from the file and the data for those attributes. If all you want are the attachments, then this is mostly garbage, but if youβre interested then you can see all the garbage by turning on debugging. If the garbage proves useful to you, then let me know how I can maybe make it more useful. (thatβs the author talking, not me bestie π)
If an error is encountered, an undefined value is returned and the package variable $errstr is set to some helpful message. thatβs your βbestie what happenedβ note. π«Ά
π methods, in their natural habitat π
read_in()β is a convienient front end forread()which takes a filename instead of a handle.read_ent()β is another convient front end forread()which can take aMIME::Entityobject (or any object with like methods, specificallyopen("r"),read($buff,$num_bytes), andclose).purge()β deletes any on-disk data that may be in the attachments of the TNEF object.message()β returns the message portion of the tnef object, if any. The thing it returns is like an attachment, but its not an attachment. For instance, it more than likely does not have a name or any attachment data.attachments()β returns a list of the attachments that the given TNEF object contains. Returns a list ref if not called in array context.data()β takes a TNEF attribute name, and returns a string value for that attribute for that attachment. Its your own problem if the string is too big for memory. If no argument is given, then the'AttachData'attribute is assumed, which is probably the attachment data youβre looking for.name()β is the same asdata(), except the attribute'AttachTitle'is the default, which returns the 8 character + 3 character extension name of the attachment.longname()β returns the long filename and extension of an attachment. This is embedded within a MAPI property of the'Attachment'attribute data, so we attempt to extract the name out of that.size()β takes an TNEF attribute name, and returns the size in bytes for the data for that attachment attribute.datahandle()β is a method for attachments which takes a TNEF attribute name, and returns the data for that attribute as a handle which is the same as aMIME::Bodyhandle. SeeMIME::Bodyfor all the applicable methods. If no argument is given, then'AttachData'is assumed.
π₯ EXAMPLES π₯
this example is long af but itβs the whole thing, verbatim, so you can see the whole workflow: mail is retrieved from a POP3 server based on header information, then it is MIME parsed, and then the TNEF contents are extracted and converted. main character energy, honestly. π
# Here's a rather long example where mail is retrieved
# from a POP3 server based on header information, then
# it is MIME parsed, and then the TNEF contents
# are extracted and converted.
use strict;
use Net::POP3;
use MIME::Parser;
use Convert::TNEF;
my $mail_dir = "mailout";
my $mail_prefix = "mail";
my $pop = new Net::POP3 ( "pop3server_name" );
my $num_msgs = $pop->login("user_name","password");
die "Can't login: $!" unless defined $num_msgs;
# Get mail by sender and subject
my $mail_out_idx = 0;
MESSAGE: for ( my $i=1; $i<= $num_msgs; $i++ ) {
my $header = join "", @{$pop->top($i)};
for ($header) {
next MESSAGE unless
/^from:.*someone\@somewhere.net/im &&
/^subject:\s*important stuff/im
}
my $fname = $mail_prefix."-".$$.++$mail_out_idx.".doc";
open (MAILOUT, ">$mail_dir/$fname")
or die "Can't open $mail_dir/$fname: $!";
# If the get() complains, you need the new libnet bundle
$pop->get($i, \*MAILOUT) or die "Can't read mail";
close MAILOUT or die "Error closing $mail_dir/$fname";
# If you want to delete the mail on the server
# $pop->delete($i);
}
close MAILOUT;
$pop->quit();
# Parse the mail message into separate mime entities
my $parser=new MIME::Parser;
$parser->output_dir("mimemail");
opendir(DIR, $mail_dir) or die "Can't open directory $mail_dir: $!";
my @files = map { $mail_dir."/".$_ } sort
grep { -f "$mail_dir/$_" and /$mail_prefix-$$-/o } readdir DIR;
closedir DIR;
for my $file ( @files ) {
my $entity=$parser->parse_in($file) or die "Couldn't parse mail";
print_tnef_parts($entity);
# If you want to delete the working files
# $entity->purge;
}
sub print_tnef_parts {
my $ent = shift;
if ( $ent->parts ) {
for my $sub_ent ( $ent->parts ) {
print_tnef_parts($sub_ent);
}
} elsif ( $ent->mime_type =~ /ms-tnef/i ) {
# Create a tnef object
my $tnef = Convert::TNEF->read_ent($ent,{output_dir=>"tnefmail"})
or die $Convert::TNEF::errstr;
for ($tnef->attachments) {
print "Title:",$_->name,"\n";
print "Data:\n",$_->data,"\n";
}
# If you want to delete the working files
# $tnef->purge;
}
}
and thatβs the example, no edits, no cap. π
π SEE ALSO π
go peek at these besties: perl(1), IO::Wrap(3), MIME::Parser(3), MIME::Entity(3), MIME::Body(3).
π CAVEATS π
caveat time, bestie. The parsing may depend on the endianness (see perlport) and width of integers on the system where the TNEF file was created. If this proves to be the case (check the debug output), Iβll see what I can do about it. so yeah, check that debug output if things get weird. π
π AUTHOR π
Douglas Wilson, dougw@cpan.org β the icon who wrote this. π
okay thatβs the whole page bestie π«Ά source/version: perl v5.40.2, date: 2024-02-25. bye and happy TNEF wrangling! β¨π
π¦ where this page comes from
- alpine 3.22: perl-convert-tnef-doc 0.18-r7 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms