Receiving Mail with IMAP4
Table of Contents | Previous | Next | Index

Messaging Access SDK Guide
Part 1. Using the Messaging Access SDK


Chapter 4
Receiving Mail with IMAP4

This chapter is an overview of using IMAP4 (Internet Message Access Protocol 4) to retrieve and manage messages remotely.

[Top]

The IMAP4 Protocol

IMAP4 (Internet Message Access Protocol, Version 4), which was developed at the University of Washington, allows clients to retrieve and manage their email messages remotely. This can be very helpful to users who access mail on several different computers.

IMAP4 also provides these capabilities:

To send mail, use SMTP (Simple Mail Transport Protocol). For more information, see Chapter 2, "Sending Mail with SMTP."

For detailed information about IMAP4, consult one of the RFCs listed, with links, in IMAP4 RFCs.

[Top]

IMAP4 Session States

An IMAP4 session progresses through several stages, or states. Within each state, only certain commands are possible.

Figure 4.1   IMAP4 Session States

Table 4.1 IMAP4 Session States and Commands

Session State Commands

All States

Commands: CAPABILITY, LOGOUT, NOOP

Non-Authenticated

Before login. User login, approval. Command: LOGIN

Authenticated

User is logged in, can perform operations involving mailboxes and mailbox management. Commands: APPEND, CREATE, DELETE, EXAMINE, LIST, LSUB, RENAME, SELECT, STATUS, SUBSCRIBE, UNSUBSCRIBE

Selected

Operations involving messages. Commands: CHECK, CLOSE, COPY, EXPUNGE, FETCH, SEARCH, STORE, UID

The client must keep track of the current session state in order to know which commands are valid.

For a table of SDK-supported IMAP4 protocol commands that lists the state in which each can be called, see Supported IMAP4 Internet Protocol Commands. For detailed information about IMAP4 and IMAP4 session states, consult one of the RFCs listed, with links, in IMAP4 RFCs.

[Top]

Steps in an IMAP4 Session

Generally, a messaging application follows these steps when using IMAP4 to receive mail and manage mailboxes and messages. These steps are listed below with links to more detailed descriptions.

Step Section with details

Create a response sink.

Creating a Response Sink

Create a client.

Creating a Client

Connect to the server.

Connecting to a Server

Log in.

Logging In and Out

Check for new messages.

Checking for New Messages

Select a mailbox.

Searching for Messages

Fetch a new message.

Fetching Message Data

Perform other message and mailbox management tasks.

IMAP4 Functions by Task

Close the mailbox.

Closing a Mailbox

[Top]

IMAP4 Function Callback Mapping

Callbacks are associated with many IMAP4 functions. For general information about the response sink and callbacks, see SDK Response Sinks for C. These callbacks are invoked by the client's imap4_processResponses function.

Functions with multi-line responses map to two or more callbacks. For example, when a function is mapped to three callbacks, the first provides a notification of the start of the operation, the second of the response, and the third that the operation is complete.

Many IMAP4 functions generate a tag (out_ppTagID) that you can use to help match the command and the response associated with it within the imap4Sink_t.taggedLine response. Remember to use imap4Tag_free to free the memory associated with these tags.

If a server error occurs, the error callback is invoked.

Table 4.2 shows which IMAP4 functions are mapped to callbacks in the imap4Sink_t structure. Table 4.3 shows which functions do not map to callbacks.

Table 4.2 Functions with Callbacks

Functions Possible Responses, Mapped to Callbacks
General Commands
imap4_connect 
error, ok
imap4_disconnect
bye 
imap4_sendCommand
rawResponse, taggedLine, error
Non-Authenticated State Commands
imap4_capability
capability, taggedLine, error
imap4_noop
exists, expunge, recent,
fetchStart, fetchFlags, fetchEnd,
taggedLine, error
imap4_login
taggedLine, error
imap4_logout
bye, taggedLine, error
Authenticated State Commands
imap4_append
taggedLine, error 
imap4_create
taggedLine, error 
imap4_delete
taggedLine, error 
imap4_examine
flags, exists, recent, 
ok, taggedLine, error
imap4_list
list, taggedLine, error 
imap4_lsub
lsub, taggedLine, error 
imap4_rename
taggedLine, error 
imap4_select
flags, exists, recent, 
ok, taggedLine, error
imap4_status
statusMessages, statusRecent, 
statusUidnext, statusUidvalidity,
statusUnseen, taggedLine, error
imap4_subscribe
taggedLine, error 
imap4_unsubscribe
taggedLine, error
Selected State Commands
imap4_check
taggedLine, error 
imap4_close
taggedLine, error 
imap4_copy
taggedLine, error 
imap4_uidCopy
taggedLine, error 
imap4_expunge
expunge, taggedLine, error 
imap4_fetch
fetchStart, fetchEnd, fetchSize, 
fetchData, fetchFlags, fetchBodyStructure,
fetchEnvelope, fetchInternalDate,
fetchHeader, fetchUid, taggedLine, error
imap4_uidFetch
fetchStart, fetchEnd, fetchSize, 
fetchData, fetchFlags, fetchBodyStructure,
fetchEnvelope, fetchInternalDate,
fetchHeader, fetchUid, taggedLine, error
imap4_search
searchStart, search, searchEnd, 
taggedLine, error
imap4_uidSearch
searchStart, search, searchEnd, 
taggedLine, error
imap4_store
taggedLine, error 
imap4_uidStore 
taggedLine, error 
Extended IMAP Commands
imap4_namespace
nameSpaceStart, nameSpacePersonal,
nameSpaceOtherUsers, nameSpaceShared,
nameSpaceEnd, taggedLine, error
imap4_setACL
taggedLine, error 
imap4_deleteACL
taggedLine, error 
imap4_getACL
aclStart, aclIdentifierRight, aclEnd, taggedLine, error 
imap4_myRights
myRights, taggedLine, error 
imap4_listRights
listRightsStart, 
listRightsRequiredRights,
listRightsOptionalRights,
listRightsEnd, taggedLine, error
Table 4.3 Functions without Callbacks

Functions Without Callbacks
imap4_free
imap4_setResponseSink
imap4_get_option
imap4_setTimeout
imap4_initialize
imap4Sink_free
imap4_processResponses
imap4Sink_initialize
imap4_setChunkSize
imap4Tag_free
imap4_set_option
[Top] [IMAP4 Function Callback Mapping]


Creating a Response Sink

The first step in starting an IMAP4 session is to initialize the IMAP4 response sink, which is defined by the imap4Sink_t structure. The response sink is made up of function pointers and opaque data. Initializing the sink sets its function pointers and opaque data to null. For general information about the response sink, see SDK Response Sinks for C.

To initialize and allocate the response sink, call the imap4Sink_initialize function. If successful, this function returns NSMAIL_OK. Use this syntax:

int imap4Sink_initialize(imap4Sink_t** out_ppimap4Sink);
The following section of code initializes the response sink and sets the sink function pointers.

int l_retCode;
imap4Sink_t* l_pimap4Sink = NULL;
l_retCode = imap4Sink_initialize( &l_pimap4Sink); 
if(l_retCode != NSMAIL_OK)   { /*Deal with error */ } 
setSinkFunctions(l_pimap4Sink); /* Set sink function pointers */
After you create the response sink, the next step is Creating a Client.

When a session is finished, you must free any memory associated with the response sink. To free the response sink and its data members, use imap4Sink_free:

int imap4Sink_free(imap4Sink_t** out_ppimap4Sink); 
When this function returns, the response sink is set to null. The user must free any opaque data.

[Top] [Creating a Response Sink]

Creating a Client

The IMAP4 client uses the imap4Client_t structure to communicate with an IMAP4 server. To initialize and allocate the imap4Client_t structure and set the response sink for the client's use, call the imap4_initialize function.

When you create the client structure, you pass in the identifier. Use this syntax:

int imap4_initialize(imap4Client_t ** in_ppimap4, 
                     imap4Sink_t* in_pimap4Sink);
The following section of code creates a client.

/* Initialize sink first as described in Creating a Response Sink */
imap4Client_t * l_pimap4Client = NULL;
l_retCode = imap4_initialize(&l_pimap4Client, l_pimap4Sink); 
if(l_retCode != NSMAIL_OK)   { /*Deal with error*/ } 
After you initialize the client, the next step is Connecting to a Server.

When a session is finished, you must free any memory associated with the client. To free the client structure and its data members, use this function:

int imap4_free(imap4Client_t ** in_ppimap4); 
The in_ppimap4 parameter represents the IMAP4 client. When this function returns, the client structure is set to null.

[Top]

Connecting to a Server

Before retrieving mail, the client must connect with the server through a service port. To connect to the server, use the imap4_connect function:

int imap4_connect(imap4Client_t * in_pimap4, 
                  const char * in_host,
                  unsigned short in_port,
                  char** out_ppTagID);
Supply the identifier of the IMAP4 client that wants to connect with the server, the identifier of the host server, and the connection port to use.

This function generates a tag that you can use to help match the command and the response associated with it. Remember to use imap4Tag_free to free the memory associated with the tag.

The following section of code connects the client to the server.

/* After Creating a Response Sink and Creating a Client */
char * l_szServer = "Server Name";
char * l_szTagID = "NULL";
l_retCode = imap4_connect(l_pimap4Client, l_szServer, 143, &l_szTagID); 
if(l_retCode != NSMAIL_OK) { /*Deal with error*/ } 
l_retCode = imap4_processResponses(l_pimap4Client); 
if(l_retCode != NSMAIL_OK) { /*Deal with error*/ } 
imap4Tag_free(&l_szTagID); 
During the connect process, you can find out what extensions the server supports. For more information, see Determining Server Capabilities. You also might want to log in. For more information, see Logging In and Out.

When a session is finished, free any memory associated with the client. To disconnect the client from the server and close the socket connection, use this function:

int imap4_disconnect( imap4Client_t * in_pimap4 );
The in_pimap4 parameter represents the IMAP4 client. You could use this function as part of a Cancel operation while retrieving a message. Remember that you do not call imap4_processResponses after imap4_disconnect.

NOTE: For the callback mapping for these functions, see IMAP4 Function Callback Mapping. §
[Top]

Determining Server Capabilities

To retrieve a listing of the capabilities that are supported by the server, call the imap4_capability function:

int imap4_capability(imap4Client_t* in_pimap4, 
                     char** out_ppTagID);
This function calls the CAPABILITY IMAP4 protocol command, which can be issued in any session state, but is usually issued after connecting to the server.

This function generates a tag that you can use to help match the command and the response associated with it. Remember to use imap4Tag_free to free the memory associated with the tag.

NOTE: For this function's callback mapping, see IMAP4 Function Callback Mapping. §
The following section of code retrieves a list of server capabilities.

/* After Connecting to a Server */
l_retCode = imap4_capability(l_pimap4Client, &out_pTagID); 
if(l_retCode != NSMAIL_OK)   { /*Deal with error*/ } 
l_retCode = imap4_processResponses(l_pimap4Client); 
if(l_retCode != NSMAIL_OK)   { /*Deal with error*/ } 
imap4Tag_free(&out_pTagID); 
[Top]

Logging In and Out

Once the client is connected to the server, the user can log in. Login identifies the client to the server. Logging in requires the identifier of the IMAP4 client, as well as the user's ID and plain text password. Use this function:

int imap4_login(imap4Client_t* in_pimap4, 
                const char* in_user,
                const char* in_password,
                char** out_ppTagID);
The function sends the LOGIN IMAP4 protocol command, which can be issued during the Non-Authenticated state. Successful login moves the IMAP4 session to the Authenticated state, where the user can search for messages and manage messages on the server.

This function generates a tag that you can use to help match the command and the response associated with it. Remember to use imap4Tag_free to free the memory associated with the tag.

The following section of code logs the user in with user name and password.

l_retCode = imap4_login(l_pimap4Client, l_szUser, l_szPassword, NULL); 
if(l_retCode != NSMAIL_OK)   { /*Deal with error*/ } 
l_retCode = imap4_processResponses(l_pimap4Client); 
if(l_retCode != NSMAIL_OK)   { /*Deal with error*/ } 
imap4Tag_free(&l_szTagID);
After you log in, the next step is Checking for New Messages.

To log out at the end of a session, use this function:

int imap4_logout(imap4Client_t* in_pimap4, char** out_ppTagID); 
Remember to use imap4Tag_free to free the memory associated with the tag this function generates.

The following section of code logs the user out.

l_retCode = imap4_logout(l_pimap4Client, &l_szTagID); 
if(l_retCode != NSMAIL_OK)   { /*Deal with error*/ } 
l_retCode = imap4_processResponses(l_pimap4Client); 
if(l_retCode != NSMAIL_OK)   { /*Deal with error*/ } 
imap4Tag_free(&l_szTagID); 
NOTE: For the callback mapping for these functions, see IMAP4 Function Callback Mapping. §
[Top]

Checking for New Messages

Most IMAP4 servers check for messages whenever a command is issued. In the absence of commands, the server does not check for messages and may disconnect. To keep the server open indefinitely and check for messages periodically, the developer can call imap4_noop at set intervals.

The imap4_noop function is ideal for polling for new mail and ensuring that the server connection is still active. imap4_noop does nothing in itself, so it only produces the side effect of resetting the autologout timer inside the server and retrieving unsolicited server responses, which all commands do. The server responses may indicate the arrival of new messages or a change in the attributes of an existing message. Use this function:

int imap4_noop(imap4Client_t* in_pimap4, char** out_ppTagID); 
The in_pimap4 parameter represents the IMAP4 client. The function generates a tag to associate with the command. Remember to use imap4Tag_free to free the memory associated with the tag.

NOTE: For this function's callback mapping, see IMAP4 Function Callback Mapping. §
The following section of code uses imap4_noop to check for messages.

l_retCode = imap4_noop(l_pimap4Client, &out_pTagID); 
if(l_retCode != NSMAIL_OK)   { /*Deal with error*/ } 
l_retCode = imap4_processResponses(l_pimap4Client); 
if(l_retCode != NSMAIL_OK)   { /*Deal with error*/ } 
imap4Tag_free(&out_pTagID); 
After checking for new messages, the next step is Searching for Messages.

[Top]

Searching for Messages

IMAP4 provides two ways to search for messages while in the Selected state. Two functions, imap4_search and imap4_uidsearch, search the currently selected mailbox and return the message numbers of messages that match a search key. These numbers can be used in turn to fetch the messages themselves.

You can supply one or more of the search keys defined in RFC 2060. Place more than one search key in a parenthesized list. For a table that summarizes the data items you can use to search, see Search Function Search Keys.

The imap4_search function searches the mailbox for messages that match the search criteria and returns their message numbers:

int imap4_search( imap4Client_t* in_pimap4, 
                  const char* in_criteria,
                  char** out_ppTagID);
This function sends the SEARCH IMAP4 protocol command, which can be issued in the Selected session state.

The imap4_uidsearch function searches the mailbox for messages specified with a unique identifier:

int imap4_uidSearch( imap4Client_t* in_pimap4, 
                     const char* in_criteria,
                     char** out_ppTagID);
This function uses the UID IMAP4 protocol command to specify that the SEARCH command uses unique message identifiers rather than sequence numbers.

This function generates a tag that you can use to help match the command and the response associated with it. Remember to use imap4Tag_free to free the memory associated with the tag.

NOTE: For the callback mapping for these functions, see IMAP4 Function Callback Mapping. §
The following section of code searches for messages that have the SUBJECT "afternoon meeting."

int l_retCode = 0; 
l_retCode = imap4_search(l_pimap4Client, "SUBJECT \"afternoon meeting\"",
&out_pTagID); 
if(l_retCode != NSMAIL_OK)   { /*Deal with error*/ } 
l_retCode = imap4_processResponses(l_pimap4Client); 
if(l_retCode != NSMAIL_OK)   { /*Deal with error*/ } 
imap4Tag_free(&out_pTagID); 
After locating messages, the next step is Fetching Message Data.

[Top]

Fetching Message Data

IMAP4 provides two functions that fetch messages while in the Selected state, imap4_fetch and imap4_uidfetch both search the currently selected mailbox and retrieve the data specified by the fetch criteria.

When you fetch messages, you supply the message set (mailbox) and one or more fetch criteria, placing more than one data item in a parenthesized list. The fetch criteria determine the information that is returned. You can fetch one or more of the data items defined in in RFC 2060. For a table that summarizes these data items, see RFC 2060 Fetch Data Items.

The imap4_fetch and imap4_uidfetch functions retrieve the data specified by the fetch criteria for the given message set.

This function performs a fetch:

int imap4_fetch(imap4Client_t* in_pimap4, 
               const char* in_msgSet,
               const char* in_fetchCriteria,
               char** out_ppTagID);
The imap4_uidfetch function performs a fetch using unique identifiers for messages:

int imap4_uidFetch(imap4Client_t* in_pimap4, 
                   const char* in_msgSet,
                   const char* in_fetchCriteria,
                   char** out_ppTagID);
This function uses the UID IMAP4 protocol command to specify that the FETCH command uses unique message identifiers rather than sequence numbers.

Both functions generate a tag that you can use to help match the commands and the responses associated with them. Remember to use imap4Tag_free to free the memory associated with the tags.

NOTE: For the callback mapping for these functions, see IMAP4 Function Callback Mapping. §
The following section of code fetches the body of the message specified by the message number.

l_retCode = imap4_fetch(l_pimap4Client, "1:2", "BODY[]", &out_pTagID); 
if(l_retCode != NSMAIL_OK)   { /*Deal with error*/ } 
l_retCode = imap4_processResponses(l_pimap4Client); 
if(l_retCode != NSMAIL_OK)   { /*Deal with error*/ } 
imap4Tag_free(&out_pTagID); 
[Top]

Closing a Mailbox

To close a mailbox, use the imap4_close function. This function sends the CLOSE IMAP4 protocol command, which closes the mailbox and removes any messages marked with the \Deleted flag. You can close the mailbox without logging out. In this case, the session moves to the parent mailbox. Use this syntax:

int imap4_close(imap4Client_t* in_pimap4, char** out_ppTagID); 
If you need to permanently delete messages without closing, call the imap4_expunge function.

This function generates a tag that you can use to help match the command and the response associated with it. Remember to use imap4Tag_free to free the memory associated with the tag.

NOTE: For this function's callback mapping, see IMAP4 Function Callback Mapping. §
The following section of code closes a mailbox.

l_retCode = imap4_close(l_pimap4Client, &out_pTagID); 
if(l_retCode != NSMAIL_OK)   { /*Deal with error*/ } 
l_retCode = imap4_processResponses(l_pimap4Client); 
if(l_retCode != NSMAIL_OK)   { /*Deal with error*/ } 
imap4Tag_free(&out_pTagID); 
[Top]

IMAP4 Functions by Task

To help you find the information you need more quickly, look for the task you want to perform in the column on the left. Then you can click the function name for further information.

NOTE: All functions that allocate tags must use imap4Tag_free to free the associated memory. §

Task Function for the task
General Functions

Connect to the IMAP server in_host through the port in_portNumber.

imap4_connect 

Disconnect from the IMAP4 server.

imap4_disconnect

Free the IMAP4 client structure and its data members.

imap4_free

Get the IO model.

imap4_get_option

Allocate space for the IMAP4 client structure.

imap4_initialize

Process the server responses for all API commands executed prior to this command.

imap4_processResponses

Send the specified command to the IMAP4 server.

imap4_sendCommand

Set the size of the message data chunk returned in fetchData.

imap4_setChunkSize

Set the IO model.

imap4_set_option

Set the response sink to the specified sink.

imap4_setResponseSink

Set the amount of time allowed to wait for data within imap4_processsResponses before returning control to the user.

imap4_setTimeout

Free the response sink.

imap4Sink_free

Allocate space for the IMAP4 sink structure.

imap4Sink_initialize

Free tags generated by a function.

imap4Tag_free
Non-Authenticated State Functions

Request a listing of capabilities that the server supports.

imap4_capability

Identify the client to the server.

imap4_login

Tell the server that the client is done with the connection.

imap4_logout

Issue a command that always succeeds and does nothing.

imap4_noop
Authenticated State Functions

Append a message to the specified mailbox.

imap4_append

Create a mailbox with the given name.

imap4_create

PERMANENTLY remove the mailbox with the given name.

imap4_delete

Select a server mailbox for read-only access.

imap4_examine

List the mailboxes.

imap4_list

Get a subset of user-defined "active" or "subscribed" names.

imap4_lsub

Rename a mailbox.

imap4_rename

Select a mailbox on the server.

imap4_select

Request the status of a particular mailbox.

imap4_status

Add a mailbox name to the server's set of "active" or "subscribed" mailboxes.

imap4_subscribe

Remove a mailbox from server's subscribed mailbox list.

imap4_unsubscribe
Selected State Functions

Request a checkpoint of the currently selected mailbox.

imap4_check

Close the mailbox.

imap4_close

Copy the specified message(s) from the currently selected mailbox to the end of the specified destination mailbox.

imap4_copy

Remove all messages flagged for deletion.

imap4_expunge

Retrieve data specified by the fetch criteria for the given message set and return the corresponding message sequence numbers.

imap4_fetch

Search the mailbox for messages that match your search criteria and retrieve the corresponding message sequence numbers.

imap4_search

Alter data associated with a message in the mailbox.

imap4_store

Copy messages specified with a unique identifier.

imap4_uidCopy

Fetch messages specified with a unique identifier and retrieve the corresponding unique identifiers.

imap4_uidFetch

Search the mailbox for messages that match your search criteria and retrieve the corresponding unique identifiers.

imap4_uidSearch

Update message data associated with a unique identifier.

imap4_uidStore 
Extended IMAP4 Functions

Remove an identifier from the access control list for a mailbox.

imap4_deleteACL

Get the access control list for a mailbox.

imap4_getACL

Find which rights you can grant a specified user to a particular mailbox.

imap4_listRights

Find which rights a user has to a mailbox.

imap4_myRights

Find the prefixes of namespaces used by a server for personal mailboxes, other user's mailboxes, and shared objects.

imap4_namespace

Change the access control list to grant permissions to an identifier for a mailbox.

imap4_setACL

[Top] [IMAP4 Functions by Task]


Table of Contents | Previous | Next | Index

Last Updated: June 3, 1998

Copyright © 1998 Netscape Communications Corporation