MailBee.NET Objects 4.0

Imap.DownloadEnvelopes Method (String, Boolean, EnvelopeParts, Int32, String[], String[])

Fetches message envelopes, bodies, headers, flags, attributes, and other message-related information from the server.

public EnvelopeCollection DownloadEnvelopes(
   string messageIndexSet,
   bool indexIsUid,
   EnvelopeParts parts,
   int bodyPreviewSize,
   string[] extraHeaders,
   string[] extraItems
);

Parameters

messageIndexSet
A message sequence string containing ordinal message numbers or UIDs. Can be composed manually or using ToString.
indexIsUid
If true, messageIndexSet is treated as a sequence of UIDs; otherwise, as a sequence of ordinal message numbers.
parts
Specifies which message elements or attributes to download.
bodyPreviewSize
If parts includes MessagePreview flag, specifies the length of the message body section (in bytes) to be downloaded in addition to the message header section; if 0, only the message header is downloaded; if -1, the entire message is downloaded.
extraHeaders
The array of names of message headers to be downloaded, or a null reference (Nothing in Visual Basic) if additional headers are not needed.
extraItems
The array of additional FETCH request items to download, or a null reference (Nothing in Visual Basic) if additional FETCH items are not needed.

Return Value

EnvelopeCollection object if message envelopes were downloaded successfully; otherwise, a null reference (Nothing in Visual Basic).

Remarks

Ordinal message numbers and UIDs are one-based (minimum value is 1, not 0). However, the returned EnvelopeCollection is zero-based. The developer can use MessageNumber or Uid properties to obtain ordinal message numbers and UIDs of the downloaded envelopes.

To specify multiple message numbers or UIDs in messageIndexSet, delimit them with comma (,) or use ranges (such as "5:10" which means "download messages in the range from message #5 to the message #10"). Wildcard character (*), can be used to specify range which spans till the last message in the folder. In particular, "1:*" means "download all messages in the folder". "1:*" is also declared as AllMessages constant.

Examples of valid message sequences: "1", "1:*", "1,2", "1:2", "5:10,12:45,99,101,105,141:*".

Note   A message sequence string may NOT contain whitespaces. The following is INCORRECT: "1, 2, 5". The correct one is: "1,2,5".

When using a range of UIDs (indexIsUid is true), it's important to understand the number of returned messages may be LESS than the length of the range (or even zero). This is because UIDs are not continuous. For instance, if the folder contains messages with UIDs 4, 5, 6, 10, and 22, the "1,2,8:20" sequence of UIDs corresponds to a single message with UID=10.

parts parameters can be used to specify which message elements to download. This allows the developer to request only required information from the server and thus reduce network traffic by not downloading unnecessary data.

Note   If certain message element, attribute, or group of elements/attributes is not requested from the server, the developer should not attempt to read the corresponding properties of Envelope objects within the returned collection. For instance, if parts didn't contain Envelope (or MailBeeEnvelope, which is a superset of Envelope), From, To, Subject, and some other properties will not return useful information. See remarks in EnvelopeParts topic for more information on dependencies between downloaded parts of FETCH response and related properties of Envelope object.

bodyPreviewSize parameter makes sense only when parts includes MessagePreview flag. When bodyPreviewSize is 0, the component will download only header section of each message (accessible via MessagePreview property). If bodyPreviewSize is larger than 0, the component will download the header and the specified count of bytes of the body. If bodyPreviewSize is -1, the entire message is returned. Methods like DownloadEntireMessage or DownloadMessageHeaders simply call DownloadEnvelopes inside and then return MessagePreview values.

extraHeaders can be used to request certain additional header fields which are not included into ENVELOPE item of FETCH response and thus not present in Envelope object properties. Alternatively, the developer may request downloading the message header by setting MessagePreview flag in parts. Thus, all header fields would be downloaded. However, if the developer wants to reduce traffic and do not download entire header sections of messages, extraHeaders should be used to retrieve specific header fields. The typical usage of extraHeaders is getting "Importance" or "X-Priority" headers.

Values specified in extraItems are passed to the IMAP4 server without alteration. Using extraItems, the developer can request any valid FETCH item from the server (for instance, the developer may request downloading the contents of certain attachment or text body part of the message via its PartID). The downloaded items can than be obtained via GetEnvelopeItem method call.

When using extraItems, it's important to remember that item names in FETCH request can be different from their counterparts in the corresponding FETCH response. E.g. if requested item name is "BODY.PEEK[3.HEADER]<0.100>", the server will return "BODY[3.HEADER]<0>" name in the response. The developer may refer to the IMAP4 protocol specification (RFC3501) for more information regarding FETCH requests and responses.

Note   Due to complexity of IMAP4 responses, some servers may return badly formed FETCH responses under certain circumstances. If MailBee detects this, it raises ErrorOccurred event and sets IsValid to false. Since this is done on per-envelope basis, some Envelope objects in the returned collection may have IsValid set to false while others - to true. Anyway, the component does not throw exception when it encounters invalid envelope. This allows the application to skip invalid response and successfully receive subsequent messages.

Exceptions

Exception TypeCondition
MailBeeExceptionAn error occurred and ThrowExceptions is true.

Example

This sample downloads "X-Priority" and "X-MS-Mail-Priority" header fields for all messages in Inbox, then finds out which messages have High priority, and downloads body structures for these messages. From the body structures, the sample code obtains which messages have attachments. Then, these messages are completely downloaded, and all attachments are saved into "C:\Temp" folder.

The sample performs search of high priority messages via downloading headers just to highlight how to download custom headers. In real world, it's more effective to use Search method for this. The sample allows the developer to change code path to using Search via setting searchViaEnvelopes variable value to false.

The sample also keeps track of invalid IMAP responses in ErrorOccurred event handler.

[C#]
using System;
using MailBee;
using MailBee.ImapMail;

class Sample
{
    // ErrorOccurred event handler.
    private static void OnErrorOccurred(object sender, ErrorEventArgs e)
    {
        if (e.Reason is MailBeeImapInvalidEnvelopeException)
        {
            MailBeeImapInvalidEnvelopeException invEnvEx =
                (MailBeeImapInvalidEnvelopeException)e.Reason;

            Console.WriteLine("Fetched data for message #" +
                invEnvEx.InvalidEnvelope.MessageNumber +
                " could not be completed parsed and will be ignored");
        }
    }

    static void Main(string[] args)
    {
        Imap imp = new Imap();

        imp.Connect("imap.somehost.com");

        imp.Login("jdoe@somehost.com", "secret");

        // Select Inbox folder.
        imp.SelectFolder("INBOX");

        // Subscribe to ErrorOccurred event to track invalid envelopes.
        // We could also subscribe before calling Login or Connect since
        // we check the type of occurred error in OnErrorOccurred handler.
        imp.ErrorOccurred += new ErrorEventHandler(OnErrorOccurred);

        EnvelopeCollection envs = null;

        // We'll collect UID of high priority messages in this collection. 
        UidCollection uids = new UidCollection();

        // If true, we'll search high priority messages using DownloadEnvelopes().
        // Otherwise, we'll use Search() method (much more effective). Thus, this
        // sample highlights both approaches.
        bool searchViaEnvelopes = true;

        // Download "X-Priority" and "X-MS-Mail-Priority" headers for each message.
        // We could have used Search() instead (just set searchViaEnvelopes=false).
        // Using Search() would be more effective. Imap.DownloadEnvelopes is used
        // here only to demonstrate how to get custom header fields from the server.
        if (searchViaEnvelopes)
        {
            envs = imp.DownloadEnvelopes(Imap.AllMessages, false,
                EnvelopeParts.Uid, 0, new string[] {"X-Priority", "X-MS-Mail-Priority"}, null);

            // For each message, determine if it's high priority.
            foreach (Envelope env in envs)
            {
                bool highPriority = false;

                if (env.IsValid)
                {
                    string priority = env.ExtraHeaders["X-Priority"];
                    if (priority != null && priority.Length > 0)
                    {
                        if (priority[0] == '1' || priority[0] == '2')
                        {
                            // X-Priority is High or Highest
                            highPriority = true;
                        }
                    }
                    else
                    {
                        priority = env.ExtraHeaders["X-MS-Mail-Priority"];
                        if (priority != null && string.Compare(priority, "High", true) == 0)
                        {
                            // X-MS-Mail-Priority is High
                            highPriority = true;
                        }
                    }
                }

                if (highPriority)
                {
                    uids.Add(env.Uid);
                }
            }
        }
        else
        {
            // To search for High-Priority messages in the most effective way, set
            // searchViaEnvelopes=false in the beginning of this sample. Search() method
            // performs the same job as the code block above but produces much less
            // traffic and consumes less resources.
            uids = (UidCollection)imp.Search(true,"OR OR HEADER \"X-Priority\" \"1\" " +
                "HEADER \"X-Priority\" \"2\" HEADER \"X-MS-Mail-Priority\" \"High\"", null);
        }

        if (uids.Count > 0)
        {
            // Download envelope structures of high priority messages.
            envs = imp.DownloadEnvelopes(uids.ToString(), true,
                EnvelopeParts.BodyStructure, 0, null, null);

            // We'll collect UID of high priority messages with attachments in this collection.
            uids = new UidCollection();

            // For each message, determine if it has attachments.
            foreach (Envelope env in envs)
            {
                if (env.IsValid)
                {
                    ImapBodyStructureCollection parts = env.BodyStructure.GetAllParts();
                    foreach (ImapBodyStructure part in parts)
                    {
                        // Detect if this part is attachment.
                        if ((part.Disposition != null &&
                            part.Disposition.ToLower() == "attachment") ||
                            (part.Filename != null &&
                            part.Filename != string.Empty) ||
                            (part.ContentType != null &&
                            part.ContentType.ToLower() == "message/rfc822"))
                        {
                            uids.Add(env.Uid);
                            break;
                        }
                    }
                }
            }

            if (uids.Count > 0)
            {
                // We could also call DownloadEntireMessages here. Internally,
                // DownloadEntireMessages would call DownloadEnvelopes with the same
                // parameters and returned MailMessageCollection where each MailMessage
                // would be taken from Envelope.MessagePreview.
                envs = imp.DownloadEnvelopes(uids.ToString(), true,
                    EnvelopeParts.MessagePreview, -1, null, null);

                foreach (Envelope env in envs)
                {
                    if (env.IsValid)
                    {
                        // Save all attachments. Note: if the folder already contains
                        // attachment with the given name, MailBee will generate unique name
                        // (e.g. pic.gif will be saved as pic[1].gif if pic.gif already exists
                        // in the target folder.
                        env.MessagePreview.Attachments.SaveAll(@"C:\Temp");
                    }
                }
            }
        }

        // Disconnect from the server.
        imp.Disconnect();
    }
}
[Visual Basic]
Imports System
Imports MailBee
Imports MailBee.ImapMail

Module Sample
    ' ErrorOccurred event handler.
    Private Sub OnErrorOccurred(ByVal sender As Object, ByVal e As ErrorEventArgs)
        If (e.Reason Is GetType(MailBeeImapInvalidEnvelopeException)) Then
            Dim invEnvEx As MailBeeImapInvalidEnvelopeException = _
                CType(e.Reason, MailBeeImapInvalidEnvelopeException)

            Console.WriteLine("Fetched data for message #" & invEnvEx.InvalidEnvelope.MessageNumber & _
                 " could not be completed parsed and will be ignored")
        End If
    End Sub

    Sub Main(ByVal args As String())
        Dim imp As New Imap

        imp.Connect("imap.somehost.com")

        imp.Login("jdoe@somehost.com", "secret")

        ' Select Inbox folder.
        imp.SelectFolder("INBOX")

        ' Subscribe to ErrorOccurred event to track invalid envelopes.
        ' We could also subscribe before calling Login or Connect since
        ' we check the type of occurred error in OnErrorOccurred handler.
        AddHandler imp.ErrorOccurred, AddressOf OnErrorOccurred

        Dim envs As EnvelopeCollection = Nothing

        ' We'll collect UID of high priority messages in this collection. 
        Dim uids As New UidCollection

        ' If true, we'll search high priority messages using DownloadEnvelopes().
        ' Otherwise, we'll use Search() method (much more effective). Thus, this
        ' sample highlights both approaches.
        Dim searchViaEnvelopes As Boolean = True

        ' Download "X-Priority" and "X-MS-Mail-Priority" headers for each message.
        ' We could have used Search() instead (just set searchViaEnvelopes=false).
        ' Using Search() would be more effective. Imap.DownloadEnvelopes is used
        ' here only to demonstrate how to get custom header fields from the server.
        If searchViaEnvelopes Then
            Dim arr As String() = {"X-Priority", "X-MS-Mail-Priority"}
            envs = imp.DownloadEnvelopes(Imap.AllMessages, False, EnvelopeParts.Uid, 0, arr, Nothing)

            ' For each message, determine if it's high priority.
            For Each env As Envelope In envs
                Dim highPriority As Boolean = False

                If env.IsValid Then
                    Dim priority As String = env.ExtraHeaders("X-Priority")
                    If Not priority Is Nothing AndAlso priority.Length > 0 Then
                        If Left(priority, 1) = "1" OrElse Left(priority, 1) = "2" Then
                            ' X-Priority is High or Highest
                            highPriority = True
                        End If
                    Else
                        priority = env.ExtraHeaders("X-MS-Mail-Priority")
                        If Not priority Is Nothing AndAlso String.Compare(priority, "High", True) = 0 Then
                            ' X-MS-Mail-Priority is High
                            highPriority = True
                        End If
                    End If
                End If

                If highPriority Then
                    uids.Add(env.Uid)
                End If
            Next
        Else
            ' To search for High-Priority messages in the most effective way, set
            ' searchViaEnvelopes=false in the beginning of this sample. Search() method
            ' performs the same job as the code block above but produces much less
            ' traffic and consumes less resources.
            uids = imp.Search(True, "OR OR HEADER ""X-Priority"" ""1"" " & _
                "HEADER ""X-Priority"" ""2"" HEADER ""X-MS-Mail-Priority"" ""High""", Nothing)

            If uids.Count > 0 Then
                ' Download envelope structures of high priority messages.
                envs = imp.DownloadEnvelopes(uids.ToString(), True, EnvelopeParts.BodyStructure, _
                    0, Nothing, Nothing)

                ' We'll collect UID of high priority messages with attachments in this collection.
                uids = New UidCollection

                ' For each message, determine if it has attachments.
                For Each env As Envelope In envs
                    If env.IsValid Then
                        Dim parts As ImapBodyStructureCollection = env.BodyStructure.GetAllParts()
                        For Each part As ImapBodyStructure In parts
                            ' Detect if this part is attachment.
                            If (Not part.Disposition Is Nothing AndAlso _
                                part.Disposition.ToLower() = "attachment") OrElse _
                                (Not part.Filename Is Nothing AndAlso _
                                part.Filename <> String.Empty) OrElse _
                                (Not part.ContentType Is Nothing AndAlso _
                                part.ContentType.ToLower() = "message/rfc822") Then

                                uids.Add(env.Uid)
                                Exit For
                            End If
                        Next
                    End If
                Next

                If uids.Count > 0 Then
                    ' We could also call DownloadEntireMessages here. Internally,
                    ' DownloadEntireMessages would call DownloadEnvelopes with the same
                    ' parameters and returned MailMessageCollection where each MailMessage
                    ' would be taken from Envelope.MessagePreview.
                    envs = imp.DownloadEnvelopes(uids.ToString(), True, EnvelopeParts.MessagePreview, _
                            -1, Nothing, Nothing)

                    For Each env As Envelope In envs
                        If env.IsValid Then
                            ' Save all attachments. Note: if the folder already contains
                            ' attachment with the given name, MailBee will generate unique name
                            ' (e.g. pic.gif will be saved as pic[1].gif if pic.gif already exists
                            ' in the target folder.
                            env.MessagePreview.Attachments.SaveAll("C:\Temp")
                        End If
                    Next
                End If
            End If
        End If

        ' Disconnect from the server.
        imp.Disconnect()
    End Sub
End Module

See Also

Imap Class | MailBee.ImapMail Namespace | Imap.DownloadEnvelopes Overload List | BeginDownloadEnvelopes | Envelope | ImapBodyStructure