NAME

Mail::IMAPTalk - IMAP client interface with lots of features

SYNOPSIS

use Mail::IMAPTalk;

$IMAP = Mail::IMAPTalk->new(
    Server   => $IMAPServer,
    Username => 'foo',
    Password => 'bar',
) || die "Failed to connect/login to IMAP server";

# Append message to folder
open(my $F, 'rfc822msg.txt');
$IMAP->append($FolderName, $F) || die $@;
close($F);

# Select folder and get first unseen message
$IMAP->select($FolderName) || die $@;
$MsgId = $IMAP->search('not', 'seen')->[0];

# Get message envelope and print some details
$MsgEV = $IMAP->fetch($MsgId, 'envelope')->{$MsgId}->{envelope};
print "From: " . $MsgEv->{From};
print "To: " . $MsgEv->{To};
print "Subject: " . $MsgEv->{Subject};

# Get message body structure
$MsgBS = $IMAP->fetch($MsgId, 'bodystructure')->{$MsgId}->{bodystructure};

# Find imap part number of text part of message
$MsgTxtHash = Mail::IMAPTalk::find_message($MsgBS);
$MsgPart = $MsgTxtHash->{text}->{'IMAP-Partnum'};

# Retrieve message text body
$MsgTxt = $IMAP->fetch($MsgId, "body[$MsgPart]")->{$MsgId}->{body};

$IMAP->logout();

DESCRIPTION

This module communicates with an IMAP server. Each IMAP server command is mapped to a method of this object.

Although other IMAP modules exist on CPAN, this has several advantages over other modules.

While the IMAP protocol does allow for asynchronous running of commands, this module is designed to be used in a synchronous manner. That is, you issue a command by calling a method, and the command will block until the appropriate response is returned. The method will then return the parsed results from the given command.

CLASS OVERVIEW

The object methods have been broken in several sections.

Sections

Method results

All methods return undef on failure. There are four main modes of failure:

In each case, some readable form of error text is placed in $@, or you can call the get_last_error() method. For commands which return responses (e.g. fetch, getacl, etc), the result is returned. See each command for details of the response result. For commands with no response but which succeed (e.g. setacl, rename, etc) the result 'ok' is generally returned.

Method parameters

All methods which send data to the IMAP server (e.g. fetch(), search(), etc) have their arguments processed before they are sent. Arguments may be specified in several ways:

CONSTANTS

These constants relate to the standard 4 states that an IMAP connection can be in. They are passed and returned from the state() method. See RFC 3501 for more details about IMAP connection states.

CONSTRUCTOR

CONNECTION CONTROL METHODS

IMAP FOLDER COMMAND METHODS

Note: In all cases where a folder name is used, the folder name is first manipulated according to the current root folder prefix as described in set_root_folder().

IMAP MESSAGE COMMAND METHODS

IMAP CYRUS EXTENSION METHODS

Methods provided by extensions to the cyrus IMAP server

Note: In all cases where a folder name is used, the folder name is first manipulated according to the current root folder prefix as described in set_root_folder().

IMAP HELPER FUNCTIONS

IMAP CALLBACKS

By default, these methods do nothing, but you can dervice from Mail::IMAPTalk and override these methods to trap any things you want to catch

FETCH RESULTS

The 'fetch' operation is probably the most common thing you'll do with an IMAP connection. This operation allows you to retrieve information about a message or set of messages, including header fields, flags or parts of the message body.

Mail::IMAPTalk will always parse the results of a fetch call into a Perl like structure, though 'bodystructure', 'envelope' and 'uid' responses may have additional parsing depending on the parse_mode state and the uid state (see below).

For an example case, consider the following IMAP commands and responses (C is what the client sends, S is the server response).

C: a100 fetch 5,6 (flags rfc822.size uid)
S: * 1 fetch (UID 1952 FLAGS (\recent \seen) RFC822.SIZE 1150)
S: * 2 fetch (UID 1958 FLAGS (\recent) RFC822.SIZE 110)
S: a100 OK Completed

The fetch command can be sent by calling:

my $Res = $IMAP->fetch('1:*', '(flags rfc822.size uid)');

The result in response will look like this:

$Res = {
  1 => {
    'uid' => 1952,
    'flags' => [ '\\recent', '\\seen' ],
    'rfc822.size' => 1150
  },
  2 => {
    'uid' => 1958,
    'flags' => [ '\\recent' ],
    'rfc822.size' => 110
  }
};

A couple of points to note:

  1. The message IDs have been turned into a hash from message ID to fetch response result.
  2. The response items (e.g. uid, flags, etc) have been turned into a hash for each message, and also changed to lower case values.
  3. Other bracketed (...) lists have become array references.

In general, this is how all fetch responses are parsed. There is one major difference however when the IMAP connection is in 'uid' mode. In this case, the message IDs in the main hash are changed to message UIDs, and the 'uid' entry in the inner hash is removed. So the above example would become:

my $Res = $IMAP->fetch('1:*', '(flags rfc822.size)');

$Res = {
  1952 => {
    'flags' => [ '\\recent', '\\seen' ],
    'rfc822.size' => 1150
  },
  1958 => {
    'flags' => [ '\\recent' ],
    'rfc822.size' => 110
  }
};

Bodystructure

When dealing with messages, we need to understand the MIME structure of the message, so we can work out what is the text body, what is attachments, etc. This is where the 'bodystructure' item from an IMAP server comes in.

C: a101 fetch 1 (bodystructure)
S: * 1 fetch (BODYSTRUCTURE ("TEXT" "PLAIN" NIL NIL NIL "QUOTED-PRINTABLE" 255 11 NIL ("INLINE" NIL) NIL))
S: a101 OK Completed

The fetch command can be sent by calling:

my $Res = $IMAP->fetch(1, 'bodystructure');

As expected, the resultant response would look like this:

$Res = {
  1 => {
    'bodystructure' => [
      'TEXT', 'PLAIN', undef, undef, undef, 'QUOTED-PRINTABLE',
        255, 11, UNDEF, [ 'INLINE', undef ], undef
    ]
  }
};

However, if you set the parse_mode(BodyStructure = 1)>, then the result would be:

$Res = {
  '1' => {
    'bodystructure' => {
      'MIME-Type' => 'text',
      'MIME-Subtype' => 'plain',
      'MIME-TxtType' => 'text/plain',
      'Content-Type' => {},
      'Content-ID' => undef,
      'Content-Description' => undef,
      'Content-Transfer-Encoding' => 'QUOTED-PRINTABLE',
      'Size' => '3569',
      'Lines' => '94',
      'Content-MD5' => undef,
      'Disposition-Type' => 'inline',
      'Content-Disposition' => {},
      'Content-Language' => undef,
      'Remainder' => [],
      'IMAP-Partnum' => ''
    }
  }
};

A couple of points to note here:

  1. All the positional fields from the bodystructure list response have been turned into nicely named key/value hash items.
  2. The MIME-Type and MIME-Subtype fields have been made lower case.
  3. An IMAP-Partnum item has been added. The value in this field can be passed as the 'section' number of an IMAP body fetch call to retrieve the text of that IMAP section.

In general, the following items are defined for all body structures:

For all bodystructures EXCEPT those that have a MIME-Type of 'multipart', the following are defined:

For bodystructures where MIME-Type is 'text', an extra item 'Lines' is defined.

For bodystructures where MIME-Type is 'message' and MIME-Subtype is 'rfc822', the extra items 'Message-Envelope', 'Message-Bodystructure' and 'Message-Lines' are defined. The 'Message-Bodystructure' item is itself a reference to an entire bodystructure hash with all the format information of the contained message. The 'Message-Envelope' item is a hash structure with the message header information. See the Envelope entry below.

For bodystructures where MIME-Type is 'multipart', an extra item 'MIME-Subparts' is defined. The 'MIME-Subparts' item is an array reference, with each item being a reference to an entire bodystructure hash with all the format information of each MIME sub-part.

For further processing, you can use the find_message() function. This will analyse the body structure and find which part corresponds to the main text/html message parts to display. You can also use the find_cid_parts() function to find CID links in an html message.

Envelope

The envelope structure contains most of the addressing header fields from an email message. The following shows an example envelope fetch (the response from the IMAP server has been neatened up here)

C: a102 fetch 1 (envelope)
S: * 1 FETCH (ENVELOPE
    ("Tue, 7 Nov 2000 08:31:21 UT"      # Date
     "FW: another question"             # Subject
     (("John B" NIL "jb" "abc.com"))    # From
     (("John B" NIL "jb" "abc.com"))    # Sender
     (("John B" NIL "jb" "abc.com"))    # Reply-To
     (("Bob H" NIL "bh" "xyz.com")      # To
      ("K Jones" NIL "kj" "lmn.com"))
     NIL                                # Cc
     NIL                                # Bcc
     NIL                                # In-Reply-To
     NIL)                               # Message-ID
   )
S: a102 OK Completed

The fetch command can be sent by calling:

my $Res = $IMAP->fetch(1, 'envelope');

And you get the idea of what the resultant response would be. Again if you change parse_mode(Envelope = 1)>, you get a neat structure as follows:

$Res = {
  '1' => {
    'envelope' => {
      'Date' => 'Tue, 7 Nov 2000 08:31:21 UT',
      'Subject' => 'FW: another question',
      'From' => '"John B" <jb@abc.com>',
      'Sender' => '"John B" <jb@abc.com>',
      'Reply-To' => '"John B" <jb@abc.com>',
      'To' => '"Bob H" <bh@xyz.com>, "K Jones" <kj@lmn.com>',
      'Cc' => '',
      'Bcc' => '',
      'In-Reply-To' => undef,
      'Message-ID' => undef,

      'From-Raw' => [ [ 'John B', undef, 'jb', 'abc.com' ] ],
      'Sender-Raw' => [ [ 'John B', undef, 'jb', 'abc.com' ] ],
      'Reply-To-Raw' => [ [ 'John B', undef, 'jb', 'abc.com' ] ],
      'To-Raw' => [
        [ 'Bob H', undef, 'bh', 'xyz.com' ],
        [ 'K Jones', undef, 'kj', 'lmn.com' ],
      ],
      'Cc-Raw' => [],
      'Bcc-Raw' => [],
    }
  }
};

All the fields here are from straight from the email headers. See RFC 822 for more details.

Annotation

If the server supports RFC 5257 (ANNOTATE Extension), then you can fetch per-message annotations.

Annotation responses would normally be returned as a a nested set of arrays. However it's much easier to access the results as a nested set of hashes, so the results are so converted if the Annotation parse mode is enabled, which is on by default.

Part of an example from the RFC

S: * 12 FETCH (UID 1123 ANNOTATION
   (/comment (value.priv "My comment"
      size.priv "10")
   /altsubject (value.priv "Rhinoceroses!"
      size.priv "13")

So the fetch command:

my $Res = $IMAP->fetch(1123, 'annotation', [ '/*', [ 'value.priv', 'size.priv' ] ]);

Would have the result:

$Res = {
  '1123' => {
    'annotation' => {
      '/comment' => {
        'value.priv' => 'My comment',
        'size.priv => 10
      },
      '/altsubject' => {
        'value.priv' => '"Rhinoceroses',
        'size.priv => 13
      }
    }
  }
}

INTERNAL METHODS

INTERNAL SOCKET FUNCTIONS

INTERNAL PARSING FUNCTIONS

PERL METHODS

SEE ALSO

Net::IMAP, Mail::IMAPClient, IMAP::Admin, RFC 3501

Latest news/details can also be found at:

http://cpan.robm.fastmail.fm/mailimaptalk/

Available on github at:

https://github.com/robmueller/mail-imaptalk/

AUTHOR

Rob Mueller cpan@robm.fastmail.fm. Thanks to Jeremy Howard <j+daemonize@howard.fm> for socket code, support and documentation setup.

COPYRIGHT AND LICENSE

Copyright (C) 2003-2016 by FastMail Pty Ltd

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