Dbx(3)

πŸ“¦
version 0.07 Β· 3 versions
, in fedora 43

πŸ¦‹ Dbx(3) β€” bestie, it's the User Contributed Perl Documentation era

okay so you found a Dbx(3) page and you're like "what is this" β€” don't worry, I got you. sit down, hydrate, let's read this together. 🫢


✨ NAME ✨

Mail::Transport::Dbx β€” Parse Outlook Express mailboxes πŸ’Œ

no literally that's the whole vibe. it parses Outlook Express mailboxes. that's the job.


✨ SYNOPSIS ✨

like, here's the whole thing in action:

use Mail::Transport::Dbx;

my $dbx = eval { Mail::Transport::Dbx->new("box.mbx") };
die $@ if $@;

for my $i (0 .. $dbx->msgcount - 1) {
    my $msg = $dbx->get($i);
    print $msg->subject;
    ...
}

# more convenient
for my $msg ($dbx->emails) {
    print $msg->subject;
    ...
}

see that last bit? the # more convenient loop? yeah. that one's the move. 🌟


✨ ABSTRACT ✨

Read dbx files (mailbox files of Outlook Express)

short. sweet. iconic. πŸ’…


✨ DESCRIPTION ✨

Mail::Transport::Dbx hands you platform independent access to Outlook Express' dbx files. no cap. You can extract subfolders, messages etc. from those, or you can use it to convert dbx archives into a more portable format (such as standard mbox format). πŸŽ€

It relies on LibDBX to do its job. Now the bad news, bestie, brace yourself: LibDBX knows nothing about the endianness of your machine, so it does not work on big-endian machines such as Macintoshs or SUNs. 😭 The good news: the author made the appropriate patches so that it in fact does work even on machines with the 'wrong' byteorder (exception: machines with an even odder byteorder such as Crays are not suppored; exception from the exception: If you buy me a Cray I'll promise to fix it. :-). πŸ’€

not me noticing "suppored" is spelled like that in the source. keeping it. it's part of the lore now. πŸ™ˆ

You have to understand the structure of .dbx files to make proper use of this module. Outlook Express keeps a couple of those files on your harddisk. For instance:

Folders.dbx
folder1.dbx
comp.lang.perl.misc.dbx

The nasty thing about that is that there are really two different kinds of such files: one that contains the actual messages, and one that merely holds references to other .dbx files. Folders.dbx could be considered the toplevel file since it lists all other available .dbx files. As for folder1.dbx and comp.lang.perl.misc.dbx you can't yet know whether they contain messages or subfolders (though comp.lang.perl.misc.dbx probably contains newsgroup messages that are treated as mere emails). πŸ¦‹


Fortunately this module gives you the information you need. A common approach would be the following:

  1. create a new Mail::Transport::Dbx object from Folders.dbx
  2. iterate over its items using the get() method
    • 2.1 if it returns a Mail::Transport::Dbx::Email => a message βœ‰οΈ
    • 2.2 if it returns a Mail::Transport::Dbx::Folder => a folder πŸ“
  3. if message
    • 3.1 call whatever method from Mail::Transport::Dbx::Email you need
  4. if folder
    • 4.1 call whatever method from Mail::Transport::Dbx::Folder you need

OR

  • 4.2 call dbx() on it to create a new Mail::Transport::Dbx object
    • 4.2.1 if dbx() returned something defined => rollback to item 2)

The confusing thing is that .dbx files may contain references to other folders that don't really exist! πŸ™ˆ If Outlook Express was used as a newsclient this is a common scenario since Folders.dbx lists all newsgroups as separate Mail::Transport::Dbx::Folder objects no matter whether you are subscribed to any of those or not. So in essence calling dbx() on a folder will only return a new object if the corresponding .dbx file exists. lowkey the most important sentence on this whole page, ngl. πŸ’œ

πŸ’… METHODS πŸ’…

okay bestie, so these are the methods for Mail::Transport::Dbx objects. buckle up, there's a lot of them, but honestly they're all giving "actually useful" πŸ’–


πŸ¦‹ the Mail::Transport::Dbx methods

  • new(filename)
  • new(filehandle-ref) β€” you can hand it either a string that's the filename, or an already-opened readable filehandle ref, and new() will build a Mail::Transport::Dbx object out of it. 🫢

This works the same whether you're opening a regular dbx file or the special Folders.dbx file that holds an overview of all the available dbx subfolders.

πŸ’€ if opening fails for literally any reason, your program will instantly die() β€” no warning, no gentle letdown. so pls wrap the constructor in an eval() and check $@:
my $dbx = eval { Mail::Transport::Dbx->new( "file.dbx" ) };
die $@ if $@;

Be careful with the filehandle option though, fr. On Windows you might need to use binmode() on your handle, otherwise the stream coming from your dbx file might get corrupted. 😭

  • msgcount β€” returns how many items are stored in the dbx structure. If you previously opened Folders.dbx, msgcount() gives you the number of subfolders in it. Otherwise it returns the number of messages. psst: "msgcount() - 1" is the index of the last item. πŸ‘‘
  • emails β€” in list context this returns all the emails contained in the file. In boolean (aka scalar) context it returns a true value if the file contains emails, and false if it contains subfolders. vibe check:
if ($dbx->emails) {
    print "I contain emails";
} else {
    print "I contain subfolders";
}

This is lowkey perfect for iterations:

for my $msg ($dbx->emails) {
    ...
}
  • subfolders β€” in list context this returns all subfolders of the current file as Mail::Transport::Dbx::Folder objects. In boolean (scalar) context it returns true if the file contains subfolders and false if it contains emails.

Remember bestie: you still have to call dbx() on these subfolders if you actually want to do something useful with them:

for my $sub ($dbx->subfolders) {
    if (my $d = $sub->dbx) {
        # $d now a proper Mail::Transport::Dbx object
        # with content
    } else {
        print "Subfolder referenced but non-existent";
    }
}
  • get(n) β€” grab the item at the n-th position. First item is at position 0, obviously. ✨ get() is actually a factory method, so it returns either a Mail::Transport::Dbx::Email or a Mail::Transport::Dbx::Folder object. Which one depends on the folder you're calling it on:
my $dbx  = Mail::Transport::Dbx->new( "Folders.dbx" );
my $item = $dbx->get(0);

$item is now definitely a Mail::Transport::Dbx::Folder object, because Folders.dbx doesn't contain emails β€” it's got references to subfolders.

You can use the is_email() and is_folder() method to check what type it is:

if ($item->is_email) {
    print $item->subject;
} else {
    # it's a subfolder
    ...
}

On an error, this method returns an undefined value. Check "$dbx->errstr" to find out what went wrong. πŸ•΅οΈ

  • errstr β€” whenever an error occurs, errstr() will contain a string giving you further help on what went wrong.
🚨 WARNING: internally it relies on a global variable, so all objects will have the same error-string! That means it only makes sense to use it right after an operation that potentially raises an error:
# example 1
my $dbx = Mail::Transport::Dbx->new("box.dbx")
    or die Mail::Transport::Dbx->errstr;

# example 2
my $msg = $dbx->get(5) or print $dbx->errstr;
  • error β€” similar to errstr(), except it returns an error code. See "Exportable constants/Error-Codes" under "EXPORT" for the codes that can be returned. πŸ”

πŸ’Œ the Mail::Transport::Dbx::Email methods

these are the methods for Mail::Transport::Dbx::Email objects, bestie:

  • as_string β€” returns the whole message (header and body) as one big string.

Heads up: the string still contains the raw newlines as used by DOSish systems (\015\012). If you want newlines represented in your operating system's native format, do this:

my $email = $msg->as_string;
$email =~ s/\015\012/\n/g;

On Windows this is a no-op, so you can totally omit this step. πŸ’…

Especially for news-articles, this method may return "undef". This always happens when that particular article was only partially downloaded (meaning only the header was retrieved from the newsserver). There is no way to retrieve this header literally with "header". Methods like "subject" etc. however do still work. πŸ™ˆ

  • header β€” returns the header-portion of the whole email.

With respect to newlines, the same as described under as_string() applies.

Returns "undef" under the same circumstances as "as_string".

  • body β€” returns the body-portion of the whole email.

With respect to newlines, the same as described under as_string() applies.

Returns "undef" under the same circumstances as "as_string".

  • subject β€” returns the subject of the email as a string.
  • psubject β€” returns the processed subject of the email as a string. "Processed" means additions such as "Re:" etc. are cut off. βœ‚οΈ
  • msgid β€” returns the message-id of the message as a string.
  • parents_ids β€” returns the message-ids of the parent messages as a string.
  • sender_name β€” returns the name of the sender of this email as a string.
  • sender_address β€” returns the address of the sender of this email as a string.
  • recip_name β€” returns the name of the recipient of this email as a string. This might be your name. ;-) 😏
  • recip_address β€” returns the address of the recipient of this email as a string.
  • oe_account_name β€” returns the Outlook Express account name this message was retrieved with, as a string.
  • oe_account_num β€” Outlook Express accounts also seem to have a numerical representation. This method will return that as a string (something like "0000001").
  • fetched_server β€” returns the name of the POP server that this message was retrieved from as a string.
  • rcvd_localtime β€” this is the exact duplicate of Perl's builtin localtime() applied to the date this message was received. It returns a string in scalar context and a list with nine elements in list context. See 'perldoc -f localtime' for details.
  • rcvd_gmtime β€” same as rcvd_localtime() but returning a date conforming to GMT.
  • date_received( [format, [len, [gmtime]]] ) β€” this method returns the date this message was received by you as a string. The date returned is calculated according to localtime().

Without additional arguments, the string returned looks something like

Sun Apr 14 02:27:57 2002

The optional first argument is a string describing the format of the date line. It's passed unchanged to strftime(3). Pls consult your system's documentation for strftime(3) to see how such a string has to look. The default string used to render the date is "%a %b %e %H:%M:%S %Y".

The optional second argument is the max string length to be returned by date_received(). This parameter is also passed unaltered to strftime(). This method uses 25 as default.

The third argument can be set to a true value if you'd rather get a date in GMT. So if you want the GMT of the date but still want to use the default rendering settings, you'll have to provide them yourself:

print $msg->date_received("%a %b %e %H:%M:%S %Y", 25, 1);
  • is_seen β€” returns a true value if this message has already been seen. False otherwise. πŸ‘€
  • is_email β€” always returns true for this kind of object.
  • is_folder β€” always returns false for this kind of object.

πŸŽ€ the Mail::Transport::Dbx::Folder methods

and these methods exist for Mail::Transport::Dbx::Folder objects:

  • dbx β€” this is a convenience method. It creates a "Mail::Transport::Dbx" object from the folder object. If the folder is only mentioned but doesn't physically exist on your hard-drive (either because you deleted the .dbx file or it was actually never there, which especially happens for newsgroup files), "dbx" returns an undefined value.

Pls read "DESCRIPTION" again to learn why dbx() can return an undefined value. 🫠

  • num β€” the index number of this folder. This is the number you passed to "$dbx->get()" to retrieve this folder.
  • type β€” according to libdbx.h this returns one of "DBX_TYPE_FOLDER" or "DBX_TYPE_EMAIL". Use it to check whether the folder contains emails or other folders.
  • name β€” the name of the folder.
  • file β€” the filename of the folder. Use this to create a new "Mail::Transport::Dbx" object:
# $folder is a Mail::Transport::Dbx::Folder object
my $new_dbx = Mail::Transport::Dbx->new( $folder->file );

Consider using the dbx() method instead. 😌

This method returns an undefined value if there is no .dbx file belonging to this folder.

  • id β€” numerical id of the folder. Not sure what this is useful for. πŸ€·β™€οΈ
  • parent_id β€” numerical id of the parent's folder.
  • folder_path β€” returns the full folder name of this folder as a list of path elements. It's then your responsibility to join them together using a delimiter that doesn't show up in any of the elements. ;-)
print join("/", $_->folder_path), "\n" for $dbx->subfolders;

# could for instance produce a long list, such as:
Outlook Express/news.rwth-aachen.de/de.comp.software.announce
Outlook Express/news.rwth-aachen.de/de.comp.software.misc
...
Outlook Express/Lokale Ordner/test/test1
Outlook Express/Lokale Ordner/test
Outlook Express/Lokale Ordner/Entwürfe
Outlook Express/Lokale Ordner/Gelâschte Objekte
Outlook Express/Lokale Ordner/Gesendete Objekte
Outlook Express/Lokale Ordner/Postausgang
Outlook Express/Lokale Ordner/Posteingang
Outlook Express/Lokale Ordner
Outlook Express/Outlook Express

Note that a slash (as any other character) might not be a safe choice, since it could show up in a folder name. 🌸

✨ EXPORT ✨

None by default. Like, you get nothing for free bestie, you gotta ask for it. πŸ™ˆ

πŸŽ€ Exportable constants

So if you wanna use any of these lil constants, you have to import them when you use() the module. You can grab the whole squad in one go like this:

use Mail::Transport::Dbx qw(:all);

Orrr you can be picky and only take the ones you actually need:

use Mail::Transport::Dbx qw(DBX_TYPE_EMAIL DBX_TYPE_FOLDER);

πŸ’œ Error-Codes

  • DBX_NOERROR β€” no error occurred. The vibe is immaculate, nothing went wrong. πŸ’–
  • DBX_BADFILE β€” a Dbx file operation failed (open or close). The file said no. 😭
  • DBX_DATA_READ β€” reading data from the dbx file failed. Couldn't get the data out, it's giving locked. πŸ’€
  • DBX_INDEXCOUNT β€” index out of range. That index is not on the guest list. 🚫
  • DBX_INDEX_OVERREAD β€” a request was made for an index reference greater than exists. You asked for more than there is, bestie, that's an overreach fr fr.
  • DBX_INDEX_UNDERREAD β€” the number of indexes read from the dbx file is less than expected. Not enough indexes came back, lowkey concerning. 🫠
  • DBX_INDEX_READ β€” reading of Index Pointer from the dbx file failed. The pointer ghosted us. πŸ‘»
  • DBX_ITEMCOUNT β€” reading of Item Count from the dbx file failed. Couldn't even count the items, embarrassing. πŸ™ˆ
  • DBX_NEWS_ITEM β€” the item is a news item, not an email. Not an email bestie, it's news. πŸ“°

πŸ¦‹ Dbx types

One of these gets returned by $folder->type so you can check whether the folder is full of emails or subfolders. Real talk tho: only DBX_TYPE_EMAIL and DBX_TYPE_FOLDER are ever returned, so even newsgroup postings are of the type DBX_TYPE_EMAIL. Periodt.

  • DBX_TYPE_EMAIL
  • DBX_TYPE_FOLDER
  • DBX_TYPE_NEWS β€” don't use this one! πŸ’€
  • DBX_TYPE_VOID β€” I have no idea what this is for. No cap, it's a mystery to me. πŸ€·β€β™€οΈ

🌈 Miscellaneous constants

  • DBX_EMAIL_FLAG_ISSEEN
  • DBX_FLAG_BODY

🌸 CAVEATS 🌸

Okay so you cannot retrieve the internal state of the objects using Data::Dumper or whatever, because Mail::Transport::Dbx uses a blessed scalar to hold a reference to the respective C structures. Which means you have to use the provided methods for each object. Call that strong encapsulation if you need a euphemism for that, bestie. πŸ’…

Also, there are currently no plans to implement write access to .dbx files. That one's left up to the authors of libdbx. Not our problem, not our era. πŸ™…β€β™€οΈ


πŸ’€ KNOWN BUGS πŸ’€

Other than that, I don't know yet of any. This, of course, has never actually been a strong indication for the absence of bugs. Make of that what you will. 🫢


πŸ”₯ SEE ALSO πŸ”₯

http://sourceforge.net/projects/ol2mbox hosts the libdbx package. It contains the library backing this module along with a description of the file format for .dbx files. Go read it, iykyk. πŸ‘‘


πŸ‘‘ AUTHOR πŸ‘‘

Tassilo von Parseval, <tassilo.von.parseval@rwth-aachen.de>


Copyright 2003-2005 by Tassilo von Parseval

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


And that's the whole page bestie! This was Dbx(3) from perl v5.42.0, dated 2025-07-25. You made it to the end, iconic behavior, slay. πŸ’–βœ¨πŸŽ€πŸ¦‹

πŸ“¦ where this page comes from