The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Mail::Box - Manage a message-folder.

SYNOPSIS

   use Mail::Box;
   my $folder = new Mail::Box file => $ENV{MAIL}, ...;
   print $folder->message(0)->subject;      # See Mail::Box::Message
   $folder->message(3)->deleted(1);
   my $emails = $folder->messages;          # amount

   $folder->addMessage(new Mail::Box::Message(...));

   foreach (@{$folder->messages}) {...}     # the messages
   foreach (@$folder) {...}                 # same

Tied-interface:

   use Mail::Box;
   tie my @inbox, 'Mail::Box', file => $ENV{MAIL};
   # See Mail::Box::Tied

DESCRIPTION

Read Mail::Box::Manager first. Mail::Box is the base-class for accessing various types of mail-folder organizational structures in a uniformal way.

This class extends:

  • Mail::Box::Threads

    implements thread detection and simplified access to the threads found.

  • Mail::Box::Locker

    implements various locking algorithms

  • Mail::Box::Tie

    provides simple array-based access to the folder.

You need to read their manual-pages too, to find-out what a folder is capable of.

The various folder-types do vary on how they store their messages (a folder with many messages in a single file or a folder as a directory with each message in a single file) Furthermore, different types of folders have different ways to be locked.

Applications usually add information to the messages in the folders, for instance whether you have replied to a message or not. The base-class for messages in a folder is Mail::Box::Message (an extention of MIME::Entity). It presents message-facts in an application-independent way. Each application needs to extend Mail::Box::Message with their own practices.

PUBLIC INTERFACE

new ARGS

(Class method) Create a new folder. The ARGS is a list of labeled parameters defining what to do. Each sub-class of Mail::Box will add different options to this method. See their manual-pages.

All possible options are: (for detail description of the Mail::Box specific options see below, for the other options their respective manual-pages)

 access            Mail::Box          'r'
 dummy_type        Mail::Box::Threads 'Mail::Box::Message::Dummy'
 folder            Mail::Box          $ENV{MAIL}
 folderdir         Mail::Box          <no default>
 lazy_extract      Mail::Box          10kb
 lockfile          Mail::Box::Locker  foldername.'.lock'
 lock_method       Mail::Box::Locker  'dotlock'
 lock_timeout      Mail::Box::Locker  1 hour
 lock_wait         Mail::Box::Locker  10 seconds
 manager           Mail::Box          undef
 message_type      Mail::Box          'Mail::Box::Message'
 notreadhead_type  Mail::Box          'Mail::Box::Message::NotReadHead'
 notread_type      Mail::Box          'Mail::Box::Message::NotParsed'
 realhead_type     Mail::Box          'MIME::Head'
 remove_when_empty Mail::Box          1
 save_on_exit      Mail::Box          1
 take_headers      Mail::Box          <specify everything you need>
 thread_body       Mail::Box::Threads 0
 thread_timespan   Mail::Box::Threads '3 days'
 thread_window     Mail::Box::Threads 10
 <none>            Mail::Box::Tie

The options added by Mail::Box

  • folder => FOLDERNAME

    Which folder to open (for read or write). When used for reading (the access option set to "r") the mailbox should already exist. When opened for "rw", we do not care, although write-permission is checked on opening.

  • access => MODE

    Access-rights to the folder. MODE can be read-only ("r"), append ("a"), and read-write ("rw"). These modes have nothing in common with the modes actually used to open the folder-files within this module.

    Folders are opened for read-only ("r") by default.

  • folderdir => DIRECTORY

    Where are folders written by default? You can specify a folder-name preceeded by = to explicitly state that the folder is located below this directory.

  • message_type => CLASS

    What kind of message-objects are stored in this type of folder. The default is Mail::Box::Message (which is a sub-class of MIME::Entity). The class you offer must be an extention of Mail::Box::Message.

  • save_on_exit => BOOL

    Sets the default on what to do when the folder is closed (see the close() method. When the program is terminated, or any other reason when the folder is automatically close, this flag determines what to do. By default, this is TRUE;

  • remove_when_empty => BOOL

    Remove the folder-file or directory (dependent on the type of folder) automatically when the write would result in a folder without sub-folders and messages. This is true by default.

  • manager => MANAGER

    The object which manages this folder. Typically a (sub-class of) Mail::Box::Manager.

Some folder-types have the following options. You can find this in their specific manual-pages. Folders which do not support these fields will not complain.

  • notread_type => CLASS

  • notreadhead_type => CLASS

  • realhead_type => CLASS

    Three classes of objects which are usually hidden for users of this module, but especially useful if you plan to extent modules. These classes all contain parts of an incompletely read message.

  • lazy_extract => INTEGER

  • lazy_extract => CODE

  • lazy_extract => METHOD

  • lazy_extract => 'NEVER'|'ALWAYS'

    If you supply a number to this option, bodies of those messages with a total size less than that number will be extracted from the folder only when nessesary. Headers will always be extracted, even from the larger messages. This reduces the memory-footprint of the program, with only little cost.

    When you supply a code-reference, that subroutine is called every time that the extraction mechanism wants to determine whether to parse the body or not. The subroutine is called:

        $code->(FOLDER, HEADER, BODY, BYTES)

    where FOLDER is a reference to the folder we are reading. HEADER refers an array of header-lines, or a MIME::Header, but may also be undef. You have to handle all three situations. BODY refers to the array lines which form the body of the message (including message-parts), but may also be undef, dependent on the folder-type. BYTES is the size of the message in bytes including the header-lines, and always defined. This may be the best way to make a selection.

    The routine must return true (be lazy: delay extract) or false (extract now).

    The third possibility is to specify the NAME of a method. In that case, for each message is called:

       FOLDER->NAME(HEADER, BODY, BYTES)

    Where each field has the same meaning as described above.

    The fourth way to use this parameter involves constants: with 'NEVER' you can disable delayed loading. With 'ALWAYS' you force unconditional delayed-loading.

    Examples: $folder->new(lazy_extract => 'NEVER'); $folder->new(lazy_extract => 10000); $folder->new(lazy_extract => sub {$_[3] >= 10000 }); #same

        $folder->new(lazy_extract => 'sent_by_me');
        sub Mail::Box::send_by_me($$$)
        {   my ($self, $header, $lines, $bytes) = @_;
            $header->get('from') =~ m/\bmy\@example.com\b/i;
        }

    The Mail::Box::Message manual-page has more on this subject.

  • take_headers => ARRAY-REGEXPS|REGEXP|'ALL'|'REAL'|'DELAY'

    When messages are not parsed (as controlled by the lazy_extract parameter), and hence stay in their respective folders, some header-lines are still to be taken: for instance you still want access to the subject-field to be able to print an index.

    See registerHeaders() below, for a detailed explanation. Please try to avoid calling that method when you can do with using this option.

    Examples: $folder->new( take_headers => 'ALL'); $folder->new( take_headers => 'Subject'); $folder->new( take_headers => [ 'X-Mutt-.*', 'X-Folder-.*' ]); $folder->new( take_headers => 'REAL' , realhead_type => 'MIME::Head' ); =back

  • clone [OPTIONS]

    Create a new folder, with the same settings as this folder. One of the specified options must be new folder to be opened. Other options overrule those of the folder where this is a clone from.

    Example: my $folder2 = $folder->clone(folder => '=jan');

  • registerHeaders REGEXP [,REGEXP, ...]

  • registeredHeaders

    See the take_header option of new(), which is the prefered way to specify which way the header should be treated. Try to avoiding registerHeaders directly.

    The registerHeaders method can be used to specify more header-lines to be taken when scanning through a folder. Its counterpart registeredHeaders returns the current setting.

    If you know your application needs some header-fields frequently, you add them to the default list of fields which are already taken by the folder-implementation. No problem if you specify the same name twice.

    If you specify too few field-names, then all messages will get parsed (read from file into memory) to get the field-data you missed. When you specify too many fields, your program will consume considerable more memory.

    You can specify a regular expression, although you cannot use parentheses in them which do count. The expressions will be matched always on the whole field. So X-.* will only match lines starting with X-. You can not used X-(ab|cd).*, but may say X-(?:ab|cd).*.

    There are three special constants. With ALL you get all header-lines from the message (same as pattern .*) and REAL will cause headers to be read into a real MIME::Header structure (to be more precise: the type you specify with realhead_type.)

    Some folder-types (like MH) support DELAY, where headers are to taken at all, until a line from the header is required. This is useful for folders where each message has to be read from a seperate source. In this case, we would like to delay even that contact as long as possible.

    • 'ALL' to indicate that all headers should be taken.

    • 'REAL'

      indicates that all headers should be taken and translated into a real MIME::Header.

    • 'DELAY'

      requests for no header at all, unless we accidentally stumble on them. This is default (and only usefull) for all folder-types which store their messages in seperate files. Mail::Box will try to avoid opening those files with maximum effort.

      In case you need header-lines, and at the same time want to avoid access to each file when a folder is opened (for instance, if you want to read e-mail in threads), consider using index-files. Read the manual-page of the folder-type you need on whether those is supported for that specific type.

    • a list of regular expressions

      which specify the header-lines to be taken.

    Examples: $folder->registerHeaders('ALL'); $folder->registerHeaders('Subject', 'X-Folder-.*');

  • unfoldHeaders REF-ARRAY

    E-mail headers may span a few lines (folded fields). The first line has the name of the field, and is followed by one or more lines which start with some blanks.

    This method receives an array, and modifies it such that folder lines are rejoined with their field-name. Don't forget to fold back again when printing to file.

  • read OPTIONS

    Read messages from the folder into the folder-structure. If there are already messages in this structure, the new ones are added.

    When to want to add messages from a different foldertype to this folder, you need to join folders, as shown in the following example.

    Example read folder into folder: my $folder = Mail::Box::File->new(folder => 'InBox'); my $old = Mail::Box::MH->new(folder => 'Received'); $folder->addMessages(@$old); $folder->write; $old->delete;

  • write [OPTIONS]

    Write the data to disk. It return true when this succeeded. If you want to write to a different file, you first create a new folder, then move the messages, and then write that file.

    As options you may specify

    • force => BOOL

      Overrule write-protection (if possible, it may still be blocked by the operating-system).

    • keep_deleted => BOOL

      Do not remove messages which were flaged to be deleted from the folder, but do remove them from disk.

    • save_deleted => BOOL

      Save messages which where flagged to be deleted. The flag is conserved (when possible)

  • close OPTIONS

    Close the folder. It depends on the OPTIONS whether the folder is to be written or not. Futhermore, you may specify options which are passed to write, as descibed above.

    Options specific to close are:

    write => 'ALWAYS'|'NEVER'|'MODIFIED'

    When must the folder be written. As could be expected, 'ALWAYS' means always (even if there are no changes), 'NEVER' means that changes to the folder will be lost, and 'MODIFIED' (which is the default) only saves the folder if there are any changes.

    force => BOOL

    Overrule the setting of access when the folder was opened. This only contributes to your program when you give it a TRUE value. However: writing to the folder not be permitted by the file-system, in which case even force will not help.

  • synchronize

    Write the messages to disk, and then read it back again. This will create a new folder structure, so you have to catch the result.

    Example: $folder = $folder->synchronize;

  • delete

    Remove the specified folder-file or folder-directory (dependent on the type of folder) from disk. Of course, THIS IS DANGEROUS: you "may" lose data.

    When you first copied this folder's information into an other folder, then be sure that that folder is written to disk first! Otherwise you may loose data in case of a system-crash or software problems.

    Examples of instance call: my $folder = Mail::Box::File->new(folder => 'InBox'); $folder->delete;

  • name

    Returns the name of this folder. What the name represents depends on the actual type of mailboxes used.

    Example: print $folder->name;

  • writeable

  • readable

    Checks whether the current folder is writeable respectively readable.

    Example: $folder->addMessage($msg) if $folder->writeable;

  • modified

  • modifications INCR

    modified checks if the folder is modified, where modifications is used to tell the folder how many changes are made in messages. The INCR value can be negative to undo effects.

  • lazyExtract HEADER, BODY, BYTES

    Calls the subroutine which will perform the chech whether a message's body should be extracted or stay in the folder until used. This method calls the routine defined by the `lazy_extract' option at creation of the folder.

  • message INDEX

    Get or set a message with on a certain index.

    Examples: my $msg = $folder->message(3); $folder->message(3)->delete; # status changes to `deleted' $folder->message(3) = $msg;

  • messageID MESSAGE-ID [,MESSAGE]

    Returns the message in this folder with the specified MESSAGE-ID. This method returns a not-parsed, parsed, or dummy message. With the second MESSAGE argument, the value is first set.

  • messages

    Returns all messages which are not scheduled to be deleted. In scalar context, it provides you with the number of undeleted messages in this folder. Dereferencing a folder to an array is overloaded to call this method.

    Examples: foreach ($folder->messages) {...} foreach (@$folder) my $remaining_size = $folder->messages;

  • activeMessage INDEX [,MESSAGE]

    Returns the message indicated by INDEX from the list of non-deleted messages. This is useful for the tied-folder interface, where we only see the non-deleted messages, but not for other purposes.

  • allMessages

    Returns a list of all messages in the folder, including those which are to be deleted.

    Examples: foreach my $msg ($folder->allMessages) { $msg->print; } my $total_size = $folder->allMessages;

  • allMessageIDs

    Returns a list of all message-ids in the folder, including those which are to be deleted.

    For some folder-types (like MH), this method may cause all message-files to be read. See their respective manual-pages.

    Examples: foreach my $id ($folder->allMessageIDs) { $folder->messageID($id)->print; }

  • addMessage MESSAGE

  • addMessages MESSAGE [, MESSAGE, ...]

    Add a message to the folder. A message is usually a Mail::Box::Message object or a sub-class of that.

    Messages with id's which allready exist in this folder are neglected.

    Examples: $folder->addMessage($msg); $folder->addMessages($msg1, $msg2, ...);

  • appendMessages LIST-OF-OPTIONS

    (Class method) Append one or more messages to an unopened folder. Usually, this method is called by the Mail::Box::Manager (its method appendMessage()), in which case the correctness of the foldertype is checked.

    This method gets a list of labeled parameters, which may contain any flag which can be used when a folder is opened (most importantly folderdir). Next to these, two parameters shall be specified:

    • folder => FOLDERNAME

      The name of the folder where the messages are to be appended. When possible, the folder-implementation will avoid to open the folder for real, because that is resource consuming.

    • message => MESSAGE

    • messages => ARRAY-OF-MESSAGES

      One reference to a MESSAGE or a reference to an ARRAY of MESSAGEs, which may be of any type. The messages will first be coerced into the correct message-type to fit in the folder, and then be added to it.

  • coerce MESSAGE

    Coerce the message to be of the correct type to be placed in the folder.

  • messageDeleted MESSAGE|MESSAGE-ID, BOOL

    Signals to the folder that a message has been deleted. This method is called automatically when you call the delete method on a MESSAGE. If the BOOL is true, the message got deleted, otherwise it got undeleted.

  • folderdir [DIR]

    Get or set the directory which is used to store mail-folders by default.

    Examples: print $folder->folderdir; $folder->folderdir("$ENV{HOME}/nsmail");

  • current [NR|MESSAGE|MESSAGE-ID]

    Returns the current message (when specified, after setting it to a new values. You may specify a NUMBER, to specify that that message-number is to be selected as current, or a MESSAGE/MESSAGE-ID (as long as you are sure that the header is already loaded, otherwise they are not recognized).

    Examples: $folder->current(0); $folder->current($message);

  • DESTROY

    This method is called by Perl when an folder-object is not accessible anymore by the rest of the program. However... This is not accomplished automatically because (unparsed) messages reference back to their folder: there is a two-way reference which is not resolved by the perl-memory cleanup.

    The two ways to clean-up the folder information is

    • by explicitly call for a close on a folder,

      in which case the data may be preserved (when the save_on_exit flag was selected), or

    • by terminating the program

      which will cause changes to be lost. In this condition, the two-way reference will cause Perl to call the DESTROY of the folder and its messages in undefined order. It is not possible to write messages which are already removed...

folder management methods

The following class methods are used to test and list folders. The do share the folderdir option, where you can specify which is the default location for the folder-files.

foundIn FOLDERNAME [,OPTIONS]

(class method) Autodetect if there is a folder of a certain type specified here. This method is extended for each type of folder.

The FOLDERNAME specifies the name of the folder, as is specified by the application. OPTIONS is a list of extra information on the request. Read the manual-page for each type of folder for more options, but at least each type will support

  • folderdir => DIRECTORY

    The location where the folders of this class are stored by default. If the user specifies a name starting with a =, that symbolizes that the name is to be found is this default DIRECTORY.

listFolders [OPTIONS]

(class method) List all folders which belong to a certain class of folders. Each class should extent this method.

At least the following options are supported, but refer to the manpage of the various folder-classes to see more options.

  • folderdir => DIRECTORY

  • check => BOOL

    Specifies whether to do a very thorrow job on selecting folders. Performing a check on each file or directory (depends on the type of folder) to see if it really contains a folder can be time-consuming, so the default is off.

  • skip_empty => BOOL

    Shall empty folders (folders which currently do not contain any messages) be included? Empty folders are not useful to open, but may be useful to save to.

subFolders [OPTIONS]

Returns a list with sub-folder names for the specified folder. Some folder-types do not have real sub-folders, but that can be simulated.

Different folder-types may carry different OPTIONS, but the following are commonly known:

  • check => 1

    Check all returned folder-names thorrowly. This will cost some performance.

Example: my @subfolders = $folder->subFolders(check => 1); if($folder->subFolders) { ... }

AUTHOR

Mark Overmeer (Mark@Overmeer.net). All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

VERSION

This code is alpha, version 0.91

30 POD Errors

The following errors were encountered while parsing the POD:

Around line 336:

Expected '=item *'

Around line 358:

Expected '=item *'

Around line 360:

Expected '=item *'

Around line 455:

Expected '=item *'

Around line 482:

Expected '=item *'

Around line 507:

Expected '=item *'

Around line 572:

Expected '=item *'

Around line 632:

Expected '=item *'

Around line 658:

Expected '=item *'

Around line 699:

Expected '=item *'

Around line 713:

Expected '=item *'

Around line 715:

Expected '=item *'

Around line 729:

Expected '=item *'

Around line 731:

Expected '=item *'

Around line 744:

Expected '=item *'

Around line 760:

Expected '=item *'

Around line 778:

Expected '=item *'

Around line 806:

Expected '=item *'

Around line 841:

Expected '=item *'

Around line 856:

Expected '=item *'

Around line 873:

Expected '=item *'

Around line 892:

Expected '=item *'

Around line 894:

Expected '=item *'

Around line 929:

Expected '=item *'

Around line 969:

Expected '=item *'

Around line 1004:

Expected '=item *'

Around line 1027:

Expected '=item *'

Around line 1044:

Expected '=item *'

Around line 1073:

Expected '=item *'

Around line 1125:

You forgot a '=back' before '=head2'

You forgot a '=back' before '=head2'