NAME
Mail::IMAPClient - An IMAP Client API
INHERITANCE
DESCRIPTION
This module provides methods implementing the IMAP protocol. It allows perl scripts to interact with IMAP message stores.
The module is used by constructing or instantiating a new IMAPClient object via the new constructor method. Once the object has been instantiated, the connect method is either implicitly or explicitly called. At that point methods are available that implement the IMAP client commands as specified in RFC2060. When processing is complete, the logoff object method should be called.
This documentation is not meant to be a replacement for RFC2060, and the wily programmer will have a copy of that document handy when coding IMAP clients.
Note that this documentation uses the term folder in place of RFC2060's use of mailbox. This documentation reserves the use of the term mailbox to refer to the set of folders owned by a specific IMAP id.
RFC2060 defines four possible states for an IMAP connection: not authenticated, authenticated, selected, and logged out. These correspond to the IMAPClient constants Connected
, Authenticated
, Selected
, and Unconnected
, respectively. These constants are implemented as class methods, and can be used in conjunction with the Status method to determine the status of an IMAPClient object and its underlying IMAP session. Note that an IMAPClient object can be in the Unconnected
state both before a server connection is made and after it has ended. This differs slightly from RFC2060, which does not define a pre-connection status. For a discussion of the methods available for examining the IMAPClient object's status, see the section labeled "Status Methods", below.
Advanced Authentication Mechanisms
RFC2060 defines two commands for authenticating to an IMAP server: LOGIN for plain text authentication and AUTHENTICATE for more secure authentication mechanisms. Currently Mail::IMAPClient supports DIGEST-MD5, CRAM-MD5, LOGIN, PLAIN (SASL), and NTLM authentication.
There are also a number of methods and parameters that you can use to build your own authentication mechanism. Since this topic is a source of many questions, I will provide a quick overview here. All of the methods and parameters discussed here are described in more detail elsewhere in this document; this section is meant to help you get started.
First of all, if you just want to do plain text authentication and your server is okay with that idea then you don't even need to read this section.
Second of all, the intent of this section is to help you implement the authentication mechanism of your choice, but you will have to understand how that mechanism works. There are lots of authentication mechanisms and most of them are not available to me to test with for one reason or another. Even if this section does not answer all of your authentication questions it does contain all the answers that I have, which I admit are scant.
Third of all, if you manage to get any advanced authentication mechanisms to work then please consider donating them to this module. I don't quite have a framework visualized for how different authentication mechanisms could "plug in" to this module but I would like to eventually see this module distributed with a number of helper modules to implement various authentication schemes.
The Mail::IMAPClient's support for add-on authentication mechanisms is pretty straight forward and is built upon several assumptions. Basically you create a callback to be used to provide the response to the server's challenge. The Authcallback parameter contains a reference to the callback, which can be an anonymous subroutine or a named subroutine. Then, you identify your authentication mechanism, either via the Authmechanism parameter or as an argument to authenticate.
You may also need to provide a subroutine to encrypt (or whatever) data before it is sent to the server. The Prewritemethod parameter must contain a reference to this subroutine. And, you will need to decrypt data from the server; a reference to the subroutine that does this must be stored in the Readmethod parameter.
This framework is based on the assumptions that a) the mechanism you are using requires a challenge-response exchange, and b) the mechanism does not fundamentally alter the exchange between client and server but merely wraps the exchange in a layer of encryption. It particularly assumes that the line-oriented nature of the IMAP conversation is preserved; authentication mechanisms that break up messages into blocks of a predetermined size may still be possible but will certainly be more difficult to implement.
Alternatively, if you have access to imtest, a utility included in the Cyrus IMAP distribution, you can use that utility to broker your communications with the IMAP server. This is quite easy to implement. An example, "imtestExample.pl" in examples, can be found in the examples
subdirectory of the source distribution.
The following list summarizes the methods and parameters that you may find useful in implementing advanced autentication:
- authenticate method
-
This method implements the AUTHENTICATE IMAP client command as documented in RFC2060. If you have set the Authmechanism parameter then the login method will call authenticate instead of doing a clear text login, which is its normal behavior. If you don't want login to call authenticate on your behalf then you can call it yourself. Instead of setting an Authmechanism you can just pass the authmechanism as the first argument to AUTHENTICATE.
- Socket and RawSocket Parameters
-
Both parameters hold a reference to the socket connection. Normally this is set for you by the connect method, but if you are implementing an advanced authentication technique you may choose to set up your own socket connection and then set this parameter manually, bypassing the connect method completely. This is also useful if you want to use IO::Socket::INET alternatives, like IO::Socket::SSL.
The RawSocket parameter simply records the socket to use for future operations, without attempting any interaction on it. In this case, you have to be sure to handle all the preliminar operations and to manually set the Mail::IMAPClient object in sync with its actual status with respect to this socket (see below for additional parameters regarding this, especially the State parameter).
The Socket parameter, instead, also attempts to carry on preliminar phases if the conditions apply. If both parameters are present, this takes the precedence over RawSocket. It is primarily used to provide an alternative socket for communications, e.g. to use IO::Socket::SSL instead of IO::Socket::INET used by connect by default.
PLEASE NOTE As of version 2.99_04 of this module, the Socket parameter has changed semantics to make it more "DWIM". The RawSocket parameter was introduced as a replacement for the Socket parameter in older version.
- State, Server, Proxy, Password, and User Parameters
-
If you need to make your own connection to the server and perform your authentication manually, then you can set these parameters to keep your Mail::IMAPClient object in sync with its actual status. Of these, only the State parameter is always necessary. The others need to be set only if you think your program will need them later.
Proxy is required for PLAIN (SASL) authentication.
- Authmechanism
-
Set this to the value that AUTHENTICATE should send to the server as the authentication mechanism. If you are brokering your own authentication then this parameter may be less useful. It is also not needed by the authenticate method. It exists solely so that you can set it when you call new to instantiate your object. The new method will call connect, who will call login. If login sees that you've set an Authmechanism then it will call authenticate, using your Authmechanism and Authcallback parameters as arguments.
- Authuser
-
Normally you authenticate and log in with the username specified in the User parameter. When you are using DIGEST-MD5 as Authmechanism, you can optionally specify a different username for the final log in. This can be useful to mark messages as seen for the Authuser if you don't know the password of the user as the seen state is often a per-user state.
- Authcallback
-
The Authcallback parameter, if set, should contain a pointer to a subroutine. The login method will use this as the callback argument to the authenticate method if the Authmechanism and Authcallback parameters are both set. If you set Authmechanism but not Authcallback then the default callback for your mechanism will be used. All supported authentication mechanisms have a default callback; in every other case not supplying the callback results in an error.
Most advanced authentication mechanisms require a challenge-response exchange. After the authenticate method sends "<tag> AUTHENTICATE <Authmechanism>\r\n" to the IMAP server, the server replies with a challenge. The authenticate method then invokes the code whose reference is stored in the Authcallback parameter as follows:
$Authcallback->($challenge,$imap)
where
$Authcallback
is the code reference stored in the Authcallback parameter,$challenge
is the challenge received from the IMAP server, and$imap
is a pointer to the Mail::IMAPClient object. The return value from the Authcallback routine should be the response to the challenge, and that return value will be sent by the authenticate method to the server. - Readmethod
-
The Readmethod parameter points to a routine that will read data from the socket connection. This read method will replace the sysread that would otherwise be performed by Mail::IMAPClient. The replacement method is called with five arguments. The first is a pointer to the Mail::IMAPClient object; the rest are the four arguments required by the sysread function. Note the third argument (which corresponds to the second argument to sysread) is a buffer to read into; this will be a pointer to a scalar. So for example if your Readmethod were just going to replace sysread without any intervening processing (which would be silly but this is just an example after all) then you would set your Readmethod like this:
$imap->Readmethod( sub { my($self) = shift; my($handle,$buffer,$count,$offset) = @_; return sysread( $handle, $$buffer, $count, $offset); } );
Note particularly the double dollar signs in
$$buffer
in the sysread call; this is not a typo! - Prewritemethod
-
The Prewritemethod, if defined, should contain a pointer to a subroutine. It is called immediately prior to writing to the socket connection. It is called by Mail::IMAPClient with two arguments: a reference to the Mail::IMAPClient object and the ASCII text string to be written. It should return another string that will be the actual string sent to the IMAP server. The idea here is that your Prewritemethod will do whatever encryption is necessary and then return the result to the caller so it in turn can be sent to the server.
- Ignoresizeerrors
-
Certain (caching) servers, like Exchange 2007, often report the wrong message size. Instead of chopping the message into a size that it fits the specified size, the reported size will be simply ignored when this parameter is set to
1
. - Supportedflags
-
Especially when
migrate()
is used, the receiving peer may need to be configured explicitly with the list of supported flags; that may be different from the source IMAP server.The names are to be specified as an ARRAY. Black-slashes and casing will be ignored.
You may also specify a CODE reference, which will be called for each of the flags seperately. In this case, the flags are not (yet) normalized. The returned lists of the CODE calls are shape the resulting flag list.
Errors
If you attempt an operation that results in an error, then you can retrieve the text of the error message by using the LastError method. However, since the LastError method is an object method (and not a class method) you will only be able to use this method if you've successfully created your object. Errors in the new method can prevent your object from ever being created. Additionally, if you supply the Server, User, and Password parameters to new, it will attempt to call connect and login, either of which could fail and cause your new method call to return undef
(in which case your object will have been created but its reference will have been discarded before ever having been returned to you).
If this happens to you, you can always check $@
. Mail::IMAPClient will populate that variable with something useful if either of the new, connect, or login methods fail. In fact, as of version 2, the $@
variable will always contain error info from the last error, so you can print that instead of calling LastError if you wish.
If you run your script with warnings turned on (which I'm sure you'll do at some point because it's such a good idea) then any error message that gets placed into the LastError slot (and/or in $@
) will automatically generate a warning.
Transactions
RFC2060 requires that each line in an IMAP conversation be prefixed with a tag. A typical conversation consists of the client issuing a tag-prefixed command string, and the server replying with one of more lines of output. Those lines of output will include a command completion status code prefixed by the same tag as the original command string.
The IMAPClient module uses a simple counter to ensure that each client command is issued with a unique tag value. This tag value is referred to by the IMAPClient module as the transaction number. A history is maintained by the IMAPClient object documenting each transaction. The Transaction method returns the number of the last transaction, and can be used to retrieve lines of text from the object's history.
The Clear parameter is used to control the size of the session history so that long-running sessions do not eat up unreasonable amounts of memory. See the discussion of Clear under "Parameters" for more information.
The Report transaction returns the history of the entire IMAP session since the initial connection or for the last Clear transactions. This provides a record of the entire conversation, including client command strings and server responses, and is a wonderful debugging tool as well as a useful source of raw data for custom parsing.
SEE ALSO
This module is part of Mail-IMAPClient distribution version 3.07, built on April 28, 2008.
LICENSE
Copyrights 2008. For other contributors see Changes.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See http://www.perl.com/perl/misc/Artistic.html