NAME
Mail::MsgStore - Complete mail client back end.
SYNOPSIS
use Mail::MsgStore;
# set mailroot
Mail::MsgStore::mailroot($ENV{MAILROOT});
# get new messages from server
$count= Mail::MsgStore::getmail(\&prompt);
# send a Mail::Internet message
Mail::MsgStore::send($msg);
# add an account
Mail::MsgStore::acct_set('Joe User <user@server.com> (work)',$password);
# delete an account
Mail::MsgStore::acct_del('Joe User <user@server.com> (work)');
# change mailroot
Mail::MsgStore::mailroot('c:/mail');
# change from address
Mail::MsgStore::from('Brian Lalonde <brianl@sd81.k12.wa.us>');
# get SMTP server address
$smtp= Mail::MsgStore::smtp;
# add message
$MsgStore{'/'}= $msg; # auto-filter
$MsgStore{'path/to/folder/'}= $msg; # add to specific folder
# delete message
delete $MsgStore{'path/to/folder/msgid'};
# delete folder
delete $MsgStore{'path/to/folder/'};
# get message
$msg= $MsgStore{'path/to/folder/msgid'};
# mark message as read, unmark 'general' flag
$MsgStore{'path/to/folder/msgid'}= 'read, -general';
# get folder's message id list
@msgids= $MsgStore{'path/to/folder/'};
# get list of folders
@folders= keys %MsgStore;
# move message
$MsgStore{'newfolder/'}= delete $MsgStore{'path/to/folder/msgid'};
# copy message
$MsgStore{'path/to/newfolder/'}= $MsgStore{'path/to/folder/msgid'};
DESCRIPTION
The primary goal of this module is ease of use. The Mail::Folder module, on top of not quite being complete yet, is a pretty low-level API. I was very impressed with how Win32::TieRegistry simplified an otherwise complex task, and decided to adopt a similar interface for handling a mail store.
Another, equally important, reason for creating this module was user-configurability. I was unhappy with existing mail clients' filtering capabilities-- I wanted to pass every new message through some arbitrary Perl code that was smart enough to forward, reply, send pages, activate emergency-type alerts, etc. based on properties of the message. What I didn't want was more bloatware--Exchange, Outlook and Groupwise have already been written, and despite being huge, still don't do enough.
Storage Format
MsgStore uses a modified form of qmail's maildir format. Here's how it works: new messages are downloaded into a file guaranteed to have a unique, but incomplete, name. The filename is completed once the entire message has been successfully downloaded (the finishing of the filename replaces maildir's state subdirectories).
The unique filename is generated as a dot-separated list of (uppercase) hexadecimal numbers: seconds past epoch (12 digits), IP address (8 digits), process id (4 digits), and download number (2 digits). The IP should guarantee uniqueness to a machine, the time and pid narrows it down to a specific process, and a simple incremental number ensures that 256 messages can be downloaded per second and still retain uniqueness. The filename also begins and ends with 'mail', also separated by dots.
Message flags are part of the message id (although requesting a message by an id with the wrong flags still works). The flags are five characters delimited by parens. Each position is either a dash (off) or a letter (on). Order is significant, but since the letters spell the word FLAGS, that shouldn't be a problem. Here are what the letters stand for:
F flame
L list/group
A answered/replied
G general/flag
S seen/opened/read
Warning
The storage format used for this module quickly becomes unusable for large message stores; hundreds or thousands of tiny files are rarely stored efficiently on the disk.
Although the module is completely usable, I hope it will inspire better storage formats to use the same simple tied-hash interface.
EVENTS
The message store allows definition of the following subroutines in the events.pl file located in the mailroot directory:
filter($msg)
-
Accepts the Mail::Internet message object. The message's recipient account is available as
X-Recipient-Account
in the message header.Returns the name of the folder that the Mail::Internet $msg belongs in. Returning undef implies the
Inbox
. Also, all message flags should be stored in theX-Msg-Info
header, either as the native(FLOR!)
format of the message ID, or the english equivalents:flame, mailing-list, opened, replied, flagged
. keep($msg)
-
Accepts the Mail::Internet message object. The message's recipient account is available as
X-Recipient-Account
in the message header.Returns a boolean value that determines whether the message should be kept on the server.
sign($msg)
-
Signs a message before it is sent.
FUNCTIONS
Sending and Receiving
getmail(\&prompt[,\&status])
-
Logs on to each mail account, checking for new messages, which are downloaded, passed to
filter()
and added.Returns number of messages downloaded. Requires a callback that will be used if there is a problem logging in:
prompt($acct)
-
Parameters:
$acct
ISA Mail::Address: user is the POP3 username, host is the POP3 server.The function must return a password, or undef to cancel. The password will be updated if it was initially set, or left blank otherwise.
status($status_message[,$percent_done])
-
Parameters:
$status_message
is a string describing what is going on suitable for GUI statusbars, etc.$percent_done
is an integer between 0 and 100 (when included, elseundef
) suitable for feeding to progress bars, etc.
signmsg($msg)
-
Signs a Mail::Internet message, using the
sign()
function from the user-defined events.pl. sendmsg($msg)
-
Sends a Mail::Internet message, and stores a copy in
Sent/
.
Settings
mailroot([$mailroot])
-
Gets/sets the root directory of the mailstore. The user's login is appended to this directory. If the directory doesn't exist, it is created. If the directory doesn't contain an events.pl file, one (fully commented) is created.
Defaults to
$ENV{MAILROOT}
or current dir unless set. load_events()
-
Reloads the events.pl file. Useful if you provide an editing facility for that file, or otherwise know that it has changed.
smtp([$smtp])
-
Gets/sets the address of the outgoing mail server.
from([$from])
-
Gets/sets the email
From:
address. accounts()
-
Returns a list of account strings.
acct_set($acct,$pwd)
-
Adds/sets an POP3 account to the list handled by
getmail()
. Parameters: account and optional password.Accounts strings are parsed by Mail::Address; the server portion is used to connect, and the user portion is used to log in. Everything else is mnemonic.
acct_del($acct)
-
Deletes an account.
The Address Book
addresses()
-
Returns a list of (references to) hashes for the entire address book.
address( field => $value, ... )
-
Add an entry to the address book. The key for the new entry is returned. The full list of fields is available in
@addr_field
, pretty names for the fields are in%addr_field
(neither exported by default).Some fields of note:
address($key)
-
Retrive the hash for an address.
address($key, field => $value, ...)
-
Update fields on an existing address. Boolean success is returned.
address($key, DELETE => 1 )
-
Delete an entry from the address book.
ldaps([$ldaps])
-
Gets/sets a comma or space-delimited list of LDAP servers.
whosearch(qr/regex/, [ @fields ] )
-
Searches the address book fields specified by fields, looking for records that match the regex, the
firstname
andlastname
fields by default. (Actually, matches with"@addr{@fields}"=~ /regex/
.) The special fieldnickname
is also checked to match. A list of (references to) hashes of matching records are returned, plus aMATCHED
field in each hash that contains the value of either$field[0]
ornickname
, depending on which field matched.The result set is sorted by matching field.
This function is probably unneccessarily complex for most mail clients.
addrsearch( -starts => $namestart, [ -number => $hitnum, ] [ -fields => \@fields, ] )
-
This is a simpler version of "whosearch" that just returns address strings (rather than entire hashrefs for each record). (Actually, matches with
"@addr{@fields}"=~ /regex/
.) By default, thefirstname
andlastname
fields are used, just as in "whosearch". The special fieldnickname
is also checked to match. In list context, the list of matching address strings is returned, but in a scalar context, the$hitnum
-th element is returned (this allows passing of a kind of "Nope, next one." request).Each address is formatted this way:
firstname
lastname
<email
> unless the match was vianickname
, in which case the nickname and a tab character are prepended to the address string. ldapsearch($startswith)
-
Searches the server(s) specified by
ldaps()
for an entry that starts with$startswith
, and returns a list similar to "addrsearch". Ignores queries shorter than 3 letters.This function is called by "addrsearch", and probably needn't be called directly.
Utility
msgsearch($folder,\&match)
-
Searches messages in
$folder
(and all subfolders) for messages that produce a true value when passed to&match
. Returns a list of fully-qualified message IDs. simplifymsg($msg)
-
Returns a text-only body of
$msg
. If the actual$msg
is amultipart/mixed
ormultipart/alternative
, for example, this just gives you the text portion of the message for display purposes. msgpath($fullqid)
-
Given a fully-qualified messsage ID (one that begins with the folder path), breaks the string into folder path and message ID. (Similar in spirit to the File::Basename module.)
msgid($msgid)
-
Given a message ID whose flags may have changed (the message ID contains the message flags), returns the new message ID.
flags($string)
-
Returns a valid flagstring for the Mail::MsgStore message ID, given either a msgid or english string (
'+read -list !flame'
) to parse. Mostly for internal use.
AUTHOR
v, <v@rant.scriptmania.com>
SEE ALSO
perl(1), Sys::UniqueId, Mail::Internet, Mail::Folder, Win32::TieRegistry, Net::LDAP, Net::POP3, Time::ParseDate