Search unanswered emails in Gmail

IMAP protocol in RFC3501 introduced \Answered flag. \Answered flag should mark messages that have been answered. This flag can by set by client applications or even by SMTP server, which can be examining In-Reply-To email headers.

Unfortunately if the message is answered through Gmail’s web interface, the \Answered flag will not be set. It will only be set if the messages were answered using an email program that sets this flag.

This means that \Answered flag can’t be used to find not-answered emails.

One option to resolve this problem is to use Gmail IMAP extensions, X-GM-THRID in particular.

We’ll connect to Gmail using IMAP – remember to use SSL and be sure to enable IMAP protocol for Gmail.

As we plan to search all emails, including sent and received ones, we’ll use CommonFolders class to get ‘All Mail’ folder.

Then we’ll get Envelope for each message. Envelope contains GmailThreadId property. It contains thread id to which this email was assigned to by Gmail.

Finally we’ll find threads that contain only one message – those are messages that were not answered.

// C#

using(Imap client = new Imap())
{
    client.ConnectSSL("imap.gmail.com");
    client.Login("pat@limilabs.com","password");

    // Select 'All Mail' folder.
    List<FolderInfo> folders = client.GetFolders();
    CommonFolders common = new CommonFolders(folders);
    client.Select(common.AllMail);

    // Get envelopes for all emails.
    List<long> uids = client.GetAll();
    List<Envelope> envelopes = client.GetEnvelopeByUID(uids);

    // Group messages by thread id.
    var threads = new Dictionary<decimal, List<Envelope>>();
    foreach (Envelope envelope in envelopes)
    {
        decimal threadId = (decimal) envelope.GmailThreadId;
        if (threads.ContainsKey(threadId) == false)
            threads[threadId] = new List<Envelope>();
        
        threads[threadId].Add(envelope);
    }

    // Find threads containing single message.
    foreach (KeyValuePair<decimal, List<Envelope>> pair in threads)
    {
        if (pair.Value.Count == 1)
        {
            Envelope envelope = pair.Value[0];
            Console.WriteLine("Gmail message id: {0}; subject: {1}", 
                envelope.GmailMessageId , 
                envelope.Subject);

        }
    }
    client.Close();
}
' VB.NET

Using client As New Imap()
	client.ConnectSSL("imap.gmail.com")
	client.Login("pat@limilabs.com", "password")

	' Select 'All Mail' folder.
	Dim folders As List(Of FolderInfo) = client.GetFolders()
	Dim common As New CommonFolders(folders)
	client.[Select](common.AllMail)

	' Get envelopes for all emails.
	Dim uids As List(Of Long) = client.GetAll()
	Dim envelopes As List(Of Envelope) = client.GetEnvelopeByUID(uids)

	' Group messages by thread id.
	Dim threads = New Dictionary(Of Decimal, List(Of Envelope))()
	For Each envelope As Envelope In envelopes
		Dim threadId As Decimal = CDec(envelope.GmailThreadId)
		If threads.ContainsKey(threadId) = False Then
			threads(threadId) = New List(Of Envelope)()
		End If

		threads(threadId).Add(envelope)
	Next

	' Find threads containing single message.
	For Each pair As KeyValuePair(Of Decimal, List(Of Envelope)) In threads
		If pair.Value.Count = 1 Then
			Dim envelope As Envelope = pair.Value(0)

			Console.WriteLine("Gmail message id: {0}; subject: {1}", _
				envelope.GmailMessageId, envelope.Subject)
		End If
	Next
	client.Close()
End Using

Tags: , , , ,

Questions?

Consider using our Q&A forum for asking any questions.