Irish Yobbo
Irish Yobbo

Reputation: 433

Creating GMail folders with Mailkit

I have an email provider that uses SMTP and IMAP from Mailkit. The main function I am using at the moment is to read messages from the inbox, and depending on the contents of the email they will go into a 'Processed' or an 'Ignored' folder. In existing systems we used with Exchange, these folders exist as subfolders to the Inbox. If the folders don't exist, they are created. A sample code snippet is below:

        var _inboxFolder = _provider.GetInboxFolder();
        var folder = _inboxFolder.GetChildFolder(folderName);
        if (folder == null)
        {
            // If Gmail, Inbox does not allow children. Check for folder in root.
            folder = _provider.GetFolder(folderName);
        }
        if (folder == null)
        {
            // Create new folder under Inbox
            folder = _inboxFolder.CreateChildFolder(folderName);
            if (folder == null)
            {
                // Cannot create under Inbox, create on root
                folder = _provider.CreateFolderOnRoot(folderName);
            }
        }

These all use my own provider which is based on an interface we use for other providers, so there is some 'strange' logic there that makes sense for the other providers. GetInboxFolder and GetFolder returns a folder, but returns null if one can't be found. This works fine in all providers - if the folders don't exist, they can be created.

The issue arrives when creating the folders. If the folders cannot be found, they should be created under the Inbox folder. If this can't happen (like in Gmail), it should create them on the root folder. However, attempting to create a folder under the Inbox folder doesn't fail, it simply creates a label called "INBOX/FolderName". Ideally I would like to have any attempt to create this folder fail so it can simply be created on the root. I imagine this is an issue in the conversion from IMAP to the GMail label system.

Is there any way of preventing the "INBOX/FolderName" label, or identifying this issue before creating it? Or is there a way of identifying that this is a gmail server and implementing a special clause for it?

For a little extra info, the CreateChildFolder and CreateFolderOnRoot code is below.

IMAPFolder Class

    public IEmailFolder CreateChildFolder(string displayName)
    {
        if (_imapClient == null || !_imapClient.IsConnected)
        {
            throw new NotLoggedInException();
        }

        return new ImapFolder(_folder.Create(displayName, true), _imapClient);
    }

IMAPClient Class

    public IEmailFolder CreateFolderOnRoot(string displayName)
    {
        if (_client == null)
        {
            throw new NotLoggedInException();
        }

        try
        {
            var toplevel = _client.GetFolder(_client.PersonalNamespaces[0]);
            var mailkit = toplevel.Create(displayName, true);
            return new ImapFolder(mailkit, _client);
        }
        catch (Exception exception)
        {
            throw new LoadFolderFailedException(exception);
        }
    }

Upvotes: 0

Views: 2114

Answers (1)

jstedfast
jstedfast

Reputation: 38643

The GMail "Label System" is how GMail implements folders. They do not implement physical folders, what they do is have "virtual" folders that are just whatever labels the user has defined and the folder is just a query of all mail that has that label applied.

That said, the GMail root namespace is string.Empty. Some IMAP servers have a root namespace of "INBOX" (such as Courier IMAP, I think).

Your CreateFolderOnRoot method should create a folder at the root for GMail, it won't create it under INBOX, so your question is very confusing.

If you want to add the folder under the INBOX, just use client.Inbox.Create (displayName, true);

The issue arrives when creating the folders. If the folders cannot be found, they should be created under the Inbox folder.

This makes me think that what you actually want to do is this:

try {
    var toplevel = _client.GetFolder(_client.PersonalNamespaces[0]);
    var mailkit = folder.GetSubfolder(displayName);
    return new ImapFolder(mailkit, _client);
} catch (Exception ex) {
    throw new LoadFolderFailedException(ex);
}

Notice the use of GetSubfolder as opposed to Create. Create will always create the folder. GetSubfolder will only get it if it exists.

Upvotes: 1

Related Questions